gnustep / libobjc2

Objective-C runtime library intended for use with Clang.
http://www.gnustep.org/
MIT License
434 stars 118 forks source link

Port build on FreeBSD 12.0-STABLE ARMv7 fails (BeagleBone Black) #83

Closed cyclaero closed 5 years ago

cyclaero commented 5 years ago

I just tried to update libobjc2 v1.8.1 to v2.0 by building the port on my BeagleBone Black, and it fails when linking the dynamic library:

FAILED: libobjc.so.4.6
: && /usr/local/bin/clang70 -fPIC -O -pipe  -fno-strict-aliasing -Xclang -fexceptions -Xclang -fobjc-exceptions -O3 -O -pipe  -fno-strict-aliasing  -pthread
-shared -Wl,-soname,libobjc.so.4.6 -o libobjc.so.4.6 CMakeFiles/objc.dir/alias_table.c.o CMakeFiles/objc.dir/block_to_imp.c.o CMakeFiles/objc.dir/caps.c.o
CMakeFiles/objc.dir/category_loader.c.o CMakeFiles/objc.dir/class_table.c.o CMakeFiles/objc.dir/dtable.c.o CMakeFiles/objc.dir/encoding2.c.o
CMakeFiles/objc.dir/hooks.c.o CMakeFiles/objc.dir/ivar.c.o CMakeFiles/objc.dir/loader.c.o CMakeFiles/objc.dir/mutation.m.o CMakeFiles/objc.dir/protocol.c.o
CMakeFiles/objc.dir/runtime.c.o CMakeFiles/objc.dir/sarray2.c.o CMakeFiles/objc.dir/selector_table.c.o CMakeFiles/objc.dir/sendmsg2.c.o
CMakeFiles/objc.dir/eh_personality.c.o CMakeFiles/objc.dir/legacy.c.o CMakeFiles/objc.dir/abi_version.c.o CMakeFiles/objc.dir/statics_loader.c.o
CMakeFiles/objc.dir/block_trampolines.S.o CMakeFiles/objc.dir/objc_msgSend.S.o CMakeFiles/objc.dir/NSBlocks.m.o CMakeFiles/objc.dir/Protocol2.m.o
CMakeFiles/objc.dir/arc.m.o CMakeFiles/objc.dir/associate.m.o CMakeFiles/objc.dir/blocks_runtime.m.o CMakeFiles/objc.dir/properties.m.o
CMakeFiles/objc.dir/gc_none.c.o CMakeFiles/objc.dir/objcxx_eh.cc.o  -lcxxrt && :
/usr/bin/ld: error: can't create dynamic relocation R_ARM_ABS32 against symbol: SmallObjectClasses in readonly segment; recompile object files with -fPIC
>>> defined in CMakeFiles/objc.dir/class_table.c.o
>>> referenced by CMakeFiles/objc.dir/objc_msgSend.S.o:(.text+0x104)

I am able to build it manually using the following CMake config in the build directory which I created in the working copy of the present repository: cmake -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_FLAGS="-fPIC" -DCMAKE_SHARED_LINKER_FLAGS="-Wl,-z,notext“ ..

davidchisnall commented 5 years ago

Please can you test the following patch? I believe it will fix the issue, but I am not 100% sure:

diff --git a/objc_msgSend.arm.S b/objc_msgSend.arm.S
index ec550fa..01064d6 100644
--- a/objc_msgSend.arm.S
+++ b/objc_msgSend.arm.S
@@ -52,9 +52,11 @@
        tst    \receiver, SMALLOBJ_MASK        // Sets Z if this is not a small int

-       itte   ne
-       ldrne  r4, LSmallIntClass              // Small Int class -> r4 if this is a small int
-       ldrne  r4, [r4]
+       ldr    r4, 6f                          // PC-relative offset of Small Int class -> r4
+42:
+       add    r4, pc                          // Address of Small Int class -> r4
+       ldr    r4, [r4]                        // Small Int class -> r4
+       it     eq
        ldreq  r4, [\receiver]                 // Load class to r4 if not a small int

        ldr    r4, [r4, #DTABLE_OFFSET]        // Dtable -> r4
@@ -123,6 +125,9 @@
 #endif
        bx     lr
 .fnend
+6:
+       .p2align 2
+       .long   SmallObjectClasses(GOT_PREL)-((42b+4)-6b)
 .endm

 .globl CDECL(objc_msgSend_fpret)
@@ -137,6 +142,3 @@ TYPE_DIRECTIVE(CDECL(objc_msgSend_stret), %function)
 CDECL(objc_msgSend_stret):
        MSGSEND r1, r2

-LSmallIntClass:
-       .long   SmallObjectClasses
-       .align  2

In particular, the +4 may be wrong, so if it doesn't work (i.e. pass the objc_msgSend test) please try tweaking that value.

davidchisnall commented 5 years ago

@ivucica is also trying to build on ARM so may be able to help here.

ivucica commented 5 years ago

I'd love to test and will eventually, but while I did just manage to build -base, I have not (yet) updated my sample Android app. So, I don't yet have anything I can run on the device to try out either libobjc2 or gnustep-base.

No ETA on that either.

cyclaero commented 5 years ago

I am working on it. However, it turns out to be not a simple yes/no test.

With the patch applied, libobjc.so builds fine, and all the test execs build fine as well. However, $BUILD/Test/objc_msgSendcrashes with segmentation fault. Then I adjusted the offset ...+4) as you suggested. Actually, I tuned it from 0 to 32 in steps of 2, only for experiencing 16 other crashes.

Then I removed the patch and tested $BUILD/Test/objc_msgSend again after building everything with -DCMAKE_SHARED_LINKER_FLAGS="-Wl,-z,notext“, and it did crash again. This lets me to assume, that something might be wrong with the objc_msgSend test, because my real world daemon which I build yesterday against libobjc2 with -DCMAKE_SHARED_LINKER_FLAGS="-Wl,-z,notext“ works without issues since, and its objects are sending/receiving messages all the time, perhaps tens of millions of times already. On the other hand, my programs use only a very tiny subset of NSObject’s functionality, and perhaps don’t trigger the issues.

Finally, I ran make test and a large number of tests fail mostly because of segmentation faults, and the test sequence even didn't come to end because test No. 91 WeakReferences_arc_legacy brings the BBB to stall, even the serial console becomes unresponsive.

For building all that, I installed llvm70 on the BBB. Today it became late already. I will run more tests in the course of tomorrow.

root@CyStat-BBB:~/install/libobjc2/build # make test
Running tests...
Test project /root/install/libobjc2/build
        Start   1: alias
  1/162 Test   #1: alias .............................................***Exception: SegFault  2.15 sec
        Start   2: alias_optimised
  2/162 Test   #2: alias_optimised ...................................***Exception: SegFault  1.54 sec
        Start   3: alias_legacy
  3/162 Test   #3: alias_legacy ......................................   Passed    0.03 sec
        Start   4: alias_legacy_optimised
  4/162 Test   #4: alias_legacy_optimised ............................   Passed    0.03 sec
        Start   5: alignTest
  5/162 Test   #5: alignTest .........................................***Exception: SegFault  1.87 sec
        Start   6: alignTest_optimised
  6/162 Test   #6: alignTest_optimised ...............................***Exception: SegFault  1.88 sec
        Start   7: alignTest_legacy
  7/162 Test   #7: alignTest_legacy ..................................   Passed    0.03 sec
        Start   8: alignTest_legacy_optimised
  8/162 Test   #8: alignTest_legacy_optimised ........................   Passed    0.03 sec
        Start   9: AllocatePair
  9/162 Test   #9: AllocatePair ......................................***Exception: SegFault  1.51 sec
        Start  10: AllocatePair_optimised
 10/162 Test  #10: AllocatePair_optimised ............................***Exception: SegFault  1.73 sec
        Start  11: AllocatePair_legacy
 11/162 Test  #11: AllocatePair_legacy ...............................   Passed    0.03 sec
        Start  12: AllocatePair_legacy_optimised
 12/162 Test  #12: AllocatePair_legacy_optimised .....................   Passed    0.03 sec
        Start  13: ARCTest_arc
 13/162 Test  #13: ARCTest_arc .......................................***Exception: SegFault  1.40 sec
        Start  14: ARCTest_arc_optimised
 14/162 Test  #14: ARCTest_arc_optimised .............................***Exception: SegFault  1.80 sec
        Start  15: ARCTest_arc_legacy
 15/162 Test  #15: ARCTest_arc_legacy ................................   Passed    0.03 sec
        Start  16: ARCTest_arc_legacy_optimised
 16/162 Test  #16: ARCTest_arc_legacy_optimised ......................   Passed    0.03 sec
        Start  17: AssociatedObject
 17/162 Test  #17: AssociatedObject ..................................***Exception: SegFault  1.47 sec
        Start  18: AssociatedObject_optimised
 18/162 Test  #18: AssociatedObject_optimised ........................***Exception: SegFault  1.41 sec
        Start  19: AssociatedObject_legacy
 19/162 Test  #19: AssociatedObject_legacy ...........................   Passed    0.03 sec
        Start  20: AssociatedObject_legacy_optimised
 20/162 Test  #20: AssociatedObject_legacy_optimised .................   Passed    0.03 sec
        Start  21: AssociatedObject2
 21/162 Test  #21: AssociatedObject2 .................................***Exception: SegFault  1.73 sec
        Start  22: AssociatedObject2_optimised
 22/162 Test  #22: AssociatedObject2_optimised .......................***Exception: SegFault  1.59 sec
        Start  23: AssociatedObject2_legacy
 23/162 Test  #23: AssociatedObject2_legacy ..........................   Passed    0.03 sec
        Start  24: AssociatedObject2_legacy_optimised
 24/162 Test  #24: AssociatedObject2_legacy_optimised ................   Passed    0.03 sec
        Start  25: BlockImpTest
 25/162 Test  #25: BlockImpTest ......................................***Exception: SegFault  2.02 sec
        Start  26: BlockImpTest_optimised
 26/162 Test  #26: BlockImpTest_optimised ............................***Exception: SegFault  1.90 sec
        Start  27: BlockImpTest_legacy
 27/162 Test  #27: BlockImpTest_legacy ...............................   Passed    0.03 sec
        Start  28: BlockImpTest_legacy_optimised
 28/162 Test  #28: BlockImpTest_legacy_optimised .....................   Passed    0.03 sec
        Start  29: BlockTest_arc
 29/162 Test  #29: BlockTest_arc .....................................***Exception: SegFault  1.32 sec
        Start  30: BlockTest_arc_optimised
 30/162 Test  #30: BlockTest_arc_optimised ...........................***Exception: SegFault  1.36 sec
        Start  31: BlockTest_arc_legacy
 31/162 Test  #31: BlockTest_arc_legacy ..............................   Passed    0.03 sec
        Start  32: BlockTest_arc_legacy_optimised
 32/162 Test  #32: BlockTest_arc_legacy_optimised ....................   Passed    0.03 sec
        Start  33: ConstantString
 33/162 Test  #33: ConstantString ....................................***Exception: SegFault  1.58 sec
        Start  34: ConstantString_optimised
 34/162 Test  #34: ConstantString_optimised ..........................***Exception: SegFault  1.60 sec
        Start  35: ConstantString_legacy
 35/162 Test  #35: ConstantString_legacy .............................   Passed    0.03 sec
        Start  36: ConstantString_legacy_optimised
 36/162 Test  #36: ConstantString_legacy_optimised ...................   Passed    0.03 sec
        Start  37: Category
 37/162 Test  #37: Category ..........................................***Exception: SegFault  1.69 sec
        Start  38: Category_optimised
 38/162 Test  #38: Category_optimised ................................***Exception: SegFault  1.20 sec
        Start  39: Category_legacy
 39/162 Test  #39: Category_legacy ...................................   Passed    0.03 sec
        Start  40: Category_legacy_optimised
 40/162 Test  #40: Category_legacy_optimised .........................   Passed    0.03 sec
        Start  41: ExceptionTest
 41/162 Test  #41: ExceptionTest .....................................***Exception: SegFault  1.63 sec
        Start  42: ExceptionTest_optimised
 42/162 Test  #42: ExceptionTest_optimised ...........................***Exception: SegFault  1.74 sec
        Start  43: ExceptionTest_legacy
 43/162 Test  #43: ExceptionTest_legacy ..............................   Passed    0.03 sec
        Start  44: ExceptionTest_legacy_optimised
 44/162 Test  #44: ExceptionTest_legacy_optimised ....................   Passed    0.03 sec
        Start  45: Forward
 45/162 Test  #45: Forward ...........................................***Exception: SegFault  1.31 sec
        Start  46: Forward_optimised
 46/162 Test  #46: Forward_optimised .................................***Exception: SegFault  1.50 sec
        Start  47: Forward_legacy
 47/162 Test  #47: Forward_legacy ....................................   Passed    0.03 sec
        Start  48: Forward_legacy_optimised
 48/162 Test  #48: Forward_legacy_optimised ..........................   Passed    0.03 sec
        Start  49: ManyManySelectors
 49/162 Test  #49: ManyManySelectors .................................***Exception: SegFault  1.68 sec
        Start  50: ManyManySelectors_optimised
 50/162 Test  #50: ManyManySelectors_optimised .......................***Exception: SegFault  1.32 sec
        Start  51: ManyManySelectors_legacy
 51/162 Test  #51: ManyManySelectors_legacy ..........................***Exception: Child aborted  6.57 sec
        Start  52: ManyManySelectors_legacy_optimised
 52/162 Test  #52: ManyManySelectors_legacy_optimised ................***Exception: Child aborted  6.41 sec
        Start  53: NestedExceptions
 53/162 Test  #53: NestedExceptions ..................................***Exception: SegFault  1.68 sec
        Start  54: NestedExceptions_optimised
 54/162 Test  #54: NestedExceptions_optimised ........................***Exception: SegFault  1.40 sec
        Start  55: NestedExceptions_legacy
 55/162 Test  #55: NestedExceptions_legacy ...........................   Passed    0.03 sec
        Start  56: NestedExceptions_legacy_optimised
 56/162 Test  #56: NestedExceptions_legacy_optimised .................   Passed    0.03 sec
        Start  57: PropertyAttributeTest
 57/162 Test  #57: PropertyAttributeTest .............................***Exception: SegFault  1.61 sec
        Start  58: PropertyAttributeTest_optimised
 58/162 Test  #58: PropertyAttributeTest_optimised ...................***Exception: SegFault  1.70 sec
        Start  59: PropertyAttributeTest_legacy
 59/162 Test  #59: PropertyAttributeTest_legacy ......................   Passed    0.03 sec
        Start  60: PropertyAttributeTest_legacy_optimised
 60/162 Test  #60: PropertyAttributeTest_legacy_optimised ............   Passed    0.03 sec
        Start  61: ProtocolExtendedProperties
 61/162 Test  #61: ProtocolExtendedProperties ........................   Passed    0.03 sec
        Start  62: ProtocolExtendedProperties_optimised
 62/162 Test  #62: ProtocolExtendedProperties_optimised ..............   Passed    0.02 sec
        Start  63: ProtocolExtendedProperties_legacy
 63/162 Test  #63: ProtocolExtendedProperties_legacy .................***Exception: SegFault  1.62 sec
        Start  64: ProtocolExtendedProperties_legacy_optimised
 64/162 Test  #64: ProtocolExtendedProperties_legacy_optimised .......***Exception: SegFault  1.79 sec
        Start  65: PropertyIntrospectionTest
 65/162 Test  #65: PropertyIntrospectionTest .........................***Exception: SegFault  1.20 sec
        Start  66: PropertyIntrospectionTest_optimised
 66/162 Test  #66: PropertyIntrospectionTest_optimised ...............***Exception: SegFault  1.68 sec
        Start  67: PropertyIntrospectionTest_legacy
 67/162 Test  #67: PropertyIntrospectionTest_legacy ..................   Passed    0.03 sec
        Start  68: PropertyIntrospectionTest_legacy_optimised
 68/162 Test  #68: PropertyIntrospectionTest_legacy_optimised ........   Passed    0.03 sec
        Start  69: PropertyIntrospectionTest2_arc
 69/162 Test  #69: PropertyIntrospectionTest2_arc ....................***Exception: SegFault  1.48 sec
        Start  70: PropertyIntrospectionTest2_arc_optimised
 70/162 Test  #70: PropertyIntrospectionTest2_arc_optimised ..........***Exception: SegFault  1.39 sec
        Start  71: PropertyIntrospectionTest2_arc_legacy
 71/162 Test  #71: PropertyIntrospectionTest2_arc_legacy .............***Exception: Child aborted  1.72 sec
        Start  72: PropertyIntrospectionTest2_arc_legacy_optimised
 72/162 Test  #72: PropertyIntrospectionTest2_arc_legacy_optimised ...***Exception: Child aborted  1.52 sec
        Start  73: ProtocolCreation
 73/162 Test  #73: ProtocolCreation ..................................***Exception: SegFault  1.41 sec
        Start  74: ProtocolCreation_optimised
 74/162 Test  #74: ProtocolCreation_optimised ........................***Exception: SegFault  1.46 sec
        Start  75: ProtocolCreation_legacy
 75/162 Test  #75: ProtocolCreation_legacy ...........................***Exception: SegFault  1.28 sec
        Start  76: ProtocolCreation_legacy_optimised
 76/162 Test  #76: ProtocolCreation_legacy_optimised .................***Exception: SegFault  1.60 sec
        Start  77: ResurrectInDealloc_arc
 77/162 Test  #77: ResurrectInDealloc_arc ............................***Exception: SegFault  1.38 sec
        Start  78: ResurrectInDealloc_arc_optimised
 78/162 Test  #78: ResurrectInDealloc_arc_optimised ..................***Exception: SegFault  1.25 sec
        Start  79: ResurrectInDealloc_arc_legacy
 79/162 Test  #79: ResurrectInDealloc_arc_legacy .....................   Passed    0.03 sec
        Start  80: ResurrectInDealloc_arc_legacy_optimised
 80/162 Test  #80: ResurrectInDealloc_arc_legacy_optimised ...........   Passed    0.03 sec
        Start  81: RuntimeTest
 81/162 Test  #81: RuntimeTest .......................................***Exception: SegFault  1.17 sec
        Start  82: RuntimeTest_optimised
 82/162 Test  #82: RuntimeTest_optimised .............................***Exception: SegFault  1.33 sec
        Start  83: RuntimeTest_legacy
 83/162 Test  #83: RuntimeTest_legacy ................................***Failed    0.03 sec
        Start  84: RuntimeTest_legacy_optimised
 84/162 Test  #84: RuntimeTest_legacy_optimised ......................***Failed    0.03 sec
        Start  85: WeakBlock_arc
 85/162 Test  #85: WeakBlock_arc .....................................***Exception: SegFault  1.75 sec
        Start  86: WeakBlock_arc_optimised
 86/162 Test  #86: WeakBlock_arc_optimised ...........................***Exception: SegFault  1.30 sec
        Start  87: WeakBlock_arc_legacy
 87/162 Test  #87: WeakBlock_arc_legacy ..............................   Passed    0.03 sec
        Start  88: WeakBlock_arc_legacy_optimised
 88/162 Test  #88: WeakBlock_arc_legacy_optimised ....................   Passed    0.03 sec
        Start  89: WeakReferences_arc
 89/162 Test  #89: WeakReferences_arc ................................***Exception: SegFault  1.49 sec
        Start  90: WeakReferences_arc_optimised
 90/162 Test  #90: WeakReferences_arc_optimised ......................***Exception: SegFault  1.36 sec
        Start  91: WeakReferences_arc_legacy
Timeout, server cystat-bbb not responding.
davidchisnall commented 5 years ago

The code path that is causing the problem is related to small objects. On 32-bit platforms, we only have one small object type, which GNUstep uses for NSNumber instances that can be represented as a 31-bit integer. These objects are stored in the high 31 bits of the pointer, with the low bit set to 1. When you send a message, objc_msgSend looks up the class from a small array of classes, rather than using the (nonexistent) isa pointer. The fix is to try to turn that into a GOT reference, but my patch from this is based on looking at the assembly that clang generates for a C version of this, so is probably buggy. It's complicated by the fact that you can't, on Thumb-2, put a label in the middle of a predicated block, so you need to pull out the PC-relative calculations and so the patch is now making it unconditionally load the address of the SmallInt class and then conditionally replace it with the value in the isa pointer if there is one.

The previous error is because the variable used to find the address of this was in the TEXT segment and so the executable part of the library needed to be modified. This is bad for security, so it's probably good that Android doesn't let you do that (or, at least, strongly discourages it).

The objc_msgSend test is a stress test of all of the functionality of objc_msgSend, including sending to large and small objects and, most excitingly, throwing an exception out of a +initialize method (if this works, pretty much everything else works - it almost never happens in practice, but it hits some quite complex code paths in the runtime), so you will find that a lot of code may work even if this test fails.

A couple of the tests (ManyManySelectors and WeakReferences_arc) will use a lot of memory, so are probably worth disabling on platforms with limited RAM.

cyclaero commented 5 years ago

I agree, the stall in the course of the WeakReferences_arc test must be attributed to a lack o memory, so let’s ignore this for the present discussion.

Anyway, I am not convinced yet that the difficulties with „small objects“ on 32bit platforms cause the crash of the objc_msgSend test on the BBB. In the meantime I put the latest snapshot of FreeBSD 13.0-CURRENT on it and this comes with clang 7.0.1. Then, I did a Debug build of the latest sources of libobjc2, having applied your „small objects“-patch to objc_msgSend.arm.S.

cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_ASM_FLAGS="-g -O0" -DCMAKE_C_FLAGS="-g -O0" -DCMAKE_CXX_FLAGS="-g -O0“ .. make lldb70 -- Tests/objc_msgSend

I was able to step over the code until TestCls = objc_getClass("MsgTest“). Then trying to step into results immediately into a crash. That means, in this particular case, we didn’t even come close to test anything:

Process 11826 stopped
* thread #1, name = 'objc_msgSend', stop reason = step in
    frame #0: 0x00012f24 objc_msgSend`main at objc_msgSend.m:180
   177  {
   178      __objc_msg_forward2 = forward;
   179      __objc_msg_forward3 = forward_slot;
-> 180      TestCls = objc_getClass("MsgTest");
   181      int exceptionThrown = 0;
   182      @try {
   183          objc_msgSend(TestCls, @selector(foo));
(lldb)
Process 11826 stopped
* thread #1, name = 'objc_msgSend', stop reason = signal SIGSEGV: invalid address (fault address: 0x4)
    frame #0: 0x20066a74
->  0x20066a74: ldr    r1, [r1, #0x4]
    0x20066a78: str    r2, [sp, #0xc]
    0x20066a7c: str    r3, [sp, #0x8]
    0x20066a80: bl     0x20085ad8
(lldb) kill
Process 11826 exited with status = -1 (0xffffffff)
cyclaero commented 5 years ago

Debugging with lldb was not very useful, because it didn’t even show where exactly in objc_getClass() the crash happened. Now I analyzed the core dump objc_msgSend.core using gdb:

Core was generated by `Test/objc_msgSend'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x20066a74 in class_table_internal_table_lookup (table=0x0, hash=727670483) at /root/install/libobjc2/hash_table.h:218
218     hash = hash % TABLE_SIZE(table);
(gdb) list
213 };
214
215 static inline PREFIX(_table_cell) PREFIX(_table_lookup)(PREFIX(_table) *table,
216                                                         uint32_t hash)
217 {
218     hash = hash % TABLE_SIZE(table);
219     return &table->table[hash];
220 }
221
222 static int PREFIX(_table_move_gap)(PREFIX(_table) *table, uint32_t fromHash,
davidchisnall commented 5 years ago

If table is null, then this sounds as if something odd is happening during initialisation. Can you send me a full back trace?

(lldb doesn't seem to find symbols for anything that happens before main, which is annoying debugging this kind of thing, but gdb from ports should work okay)

cyclaero commented 5 years ago

If table is null, then this sounds as if something odd is happening during initialisation. Can you send me a full back trace?

Sorry David, I did not see your response in time, and by chance came to it only today. Here comes the full gdb backtrace:

(gdb) bt full
#0  0x20066a8c in class_table_internal_table_lookup (table=0x0, hash=727670483) at /root/install/libobjc2/hash_table.h:218
No locals.
#1  0x2006701c in class_table_internal_table_get_cell (table=0x0, key=0x10aab) at /root/install/libobjc2/hash_table.h:338
        hash = 727670483
        cell = 0x2003303c <rtld_bind_lock>
#2  0x20064e5c in class_table_internal_table_get (table=0x0, key=0x10aab) at /root/install/libobjc2/hash_table.h:434
        cell = 0x20039200
#3  0x20064e14 in class_table_get_safe (class_name=0x10aab "MsgTest") at /root/install/libobjc2/class_table.c:131
No locals.
#4  0x2006553c in objc_getClass (name=0x10aab "MsgTest") at /root/install/libobjc2/class_table.c:546
        class = 0xbfbfec5c
#5  0x00012f38 in main () at /root/install/libobjc2/Test/objc_msgSend.m:180
        exceptionThrown = 0
        a = 0xbfbfec54
        ret = {a = 1, b = 0, c = 0, d = 0, e = -1077941156}
        f = 0xbfbfec54

I saw your conversation on the other issue #92. Since it seems to be related to a certain extend to this one, would it be helpful for you, if I provide ssh access to my BeagleBone Black? I track FreeBSD 13-CURRENT on it and it got clang 7.0.1 on board.

davidchisnall commented 5 years ago

SSH access would be very useful, yes. You're somehow getting into main before the runtime is initialised, which shouldn't be possible. I suspect that there's a linker or rtld bug that's preventing the initialisers from being called.

cyclaero commented 5 years ago

Please send me an e-mail to o...p@c...o.com (this is a onetime address), and please attach a text file with a SSH public key. I will add this key to the known hosts of the BBB and return to you the public address of the ssh server.

davidchisnall commented 5 years ago

It appears as if the generated code is never calling __objc_load. A simple test case shows that FreeBSD/ARM does not call the .ctors array at all, only .init_array. This will need a compiler change to address, unfortunately.

cyclaero commented 5 years ago

Thank you very much for looking into this. Fortunately (for me), my Objective-C code, which is targeted to ARM, does use only the most basic libobjc2 functionality and doesn’t seem to suffer from this. Since it is still under development, I will simply go on. However, I would be glad to see the issue addressed somehow before deployment.

davidchisnall commented 5 years ago

Anything using the v2 ABI will hit this, unfortunately. I don't know if it's an issue on Android, or only on FreeBSD.

cyclaero commented 5 years ago

There seemed to have been some efforts to call .ctors and .dtors as part of .init_array. See: https://reviews.llvm.org/D45508

I cannot tell, whether this made it into any actual llvm on FreeBSD.

cyclaero commented 5 years ago

On my x86_64 machine, ld.lld80 does happily accept --no-ctors-in-init-array

davidchisnall commented 5 years ago

It doesn't appear so. I have a clang patch to make it use init_array on platforms that prefer this and I've landed a patch that will let the runtime handle the initialiser being called twice, so it is safe to combine .o files that use .init_array and ones that use .ctors.

cyclaero commented 5 years ago

Perhaps the objc initializer is actually called but the initialized vars are not maintained. Only yesterday an issue with TLS in shared libraries on 32bit ARM bubbled up and has been fixed already: see: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236880

davidchisnall commented 5 years ago

I don't think so. I wrote a small test case:

#include <stdio.h>

static int did_init;

static void init(void)
{
        did_init = 1;
}

__attribute__((section(".init_array")))
//__attribute__((section(".ctors")))
void(*ctor)(void) = init;

int main(void)
{
        printf("Init? %d\n", did_init);
}

This version works, but if you uncomment the line then it doesn't (but works fine on x86-64). Do you have a clang build on the ARM machine? If so, I can do a quick incremental build with the patch applied, if not it will probably take a day or two to build on a BBB.

cyclaero commented 5 years ago

I had a clang build on the BBB, however this did not work anymore with the advent of llvm6 and even for llvm5 I needed set the parallel compile and link jobs to 1, and the build type to either Debug or MinSizeRel for the build completed. So no, and I am almost sure that actual llvm versions won’t built on the BBB anymore.

I got a setup of a CURRENT world/kernel build environment for the BBB on a 4.2 GHz quad core i7. Are you talking about the patch mentioned in the said PR, or about another patch of yours.

In the first case, I just started a make buildworld after svn update (r345732), and I would only need to transfer the new llvm binaries to the BBB.

In the second case, I could try to apply your patch to the sources of clang in the base system, and recompile again. This would have the benefit, that this could easily made it into a new PR on bugs.freebsd.org - if it works out, of course.

davidchisnall commented 5 years ago

Can you apply this clang patch (to either clang in the base system or the port)?

--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -1514,7 +1514,12 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
     if (CGM.getTriple().isOSBinFormatCOFF())
         InitVar->setSection(".CRT$XCLz");
     else
-      InitVar->setSection(".ctors");
+    {
+      if (CGM.getCodeGenOpts().UseInitArray)
+          InitVar->setSection(".ctors");
+      else
+          InitVar->setSection(".init_array");
+    }
     InitVar->setVisibility(llvm::GlobalValue::HiddenVisibility);
     InitVar->setComdat(TheModule.getOrInsertComdat(".objc_ctor"));
     CGM.addUsedGlobal(InitVar);

I have a fix for the relocation issue, which I will commit soon.

There also appears to be a problem with exceptions. This is probably FreeBSD-specific, and it appears to be a problem in the C unwinder, not the Objective-C code.

cyclaero commented 5 years ago

Done. I applied the patch to clang in base and incrementally rebuilt world. A new CGObjCGNU.o has been generated and linked into a new libclang.a and a new clang. On the BBB, I placed the original clang and it’s 5 hard links into /usr/bin/clang.orig and copied the just built new clang and 5 hard links over to the just freed places.

clang --version gives now:

FreeBSD clang version 8.0.0 (tags/RELEASE_800/final 356365) (based on LLVM 8.0.0)
Target: armv7-unknown-freebsd13.0-gnueabihf
Thread model: posix
InstalledDir: /usr/bin

Seems that just recently, clang was updated to 8.0 in CURRENT. Please let me know, if I need to copy over more of llvm from the just newly built ARM world.

davidchisnall commented 5 years ago

Thanks. It looks as if I had the condition the wrong way around in the patch, but at least I can fudge it by passing -fno-use-init-array. With that, most of the tests are now passing.

The objc_msgSend test is still failing, these are failing:

      5 - alignTest (Child aborted)
      6 - alignTest_optimised (Child aborted)

Not sure why, I'll investigate. I think the next set should pass, but are running out of memory:

     49 - ManyManySelectors (Child aborted)
     50 - ManyManySelectors_optimised (Child aborted)
     51 - ManyManySelectors_legacy (Child aborted)
     52 - ManyManySelectors_legacy_optimised (Child aborted)
     89 - WeakReferences_arc (SEGFAULT)
     90 - WeakReferences_arc_optimised (SEGFAULT)
     91 - WeakReferences_arc_legacy (SEGFAULT)
     92 - WeakReferences_arc_legacy_optimised (SEGFAULT)

These fail due to exceptions not working correctly:

    109 - objc_msgSend (SEGFAULT)
    110 - objc_msgSend_optimised (SEGFAULT)
    111 - objc_msgSend_legacy (SEGFAULT)
    112 - objc_msgSend_legacy_optimised (SEGFAULT)
    155 - CXXExceptions (SEGFAULT)
    156 - CXXExceptions_optimised (SEGFAULT)
    157 - CXXExceptions_legacy (SEGFAULT)
    158 - CXXExceptions_legacy_optimised (SEGFAULT)
    163 - ObjCXXEHInterop (SEGFAULT)
    164 - ObjCXXEHInterop_optimised (SEGFAULT)
    165 - ObjCXXEHInterop_legacy (SEGFAULT)
    166 - ObjCXXEHInterop_legacy_optimised (SEGFAULT)
davidchisnall commented 5 years ago

It looks as if alignTest was failing because the test depends on ABI alignment being stronger than it is on ARM, so that's a bug in the test not the runtime.

cyclaero commented 5 years ago

The condition should have been:

  if (CGM.getCodeGenOpts().UseInitArray)
      InitVar->setSection(".init_array");
  else
      InitVar->setSection(".ctors");

Shouldn’t it? I corrected it in CGObjCGNU.cpp and another build is running now.

cyclaero commented 5 years ago

Ready. I copied the corrected version of clang to /root/clang. I do not want to interfere with your ongoing work. Therefore, once it is convenient for you, please feel free to move it over to /usr/bin/clang and then please create the respective hard links to it, i.e. /usr/bin/c++, /usr/bin/cc, /usr/bin/clang-cpp, /usr/bin/clang++, /usr/bin/cpp.

cyclaero commented 5 years ago

With respect to the tests running out of memory, I could mount an USB stick for providing let’s say 1 GB of swap space. For this I need to restart the BBB, please let me know if I should do it, and in case yes, also when.

davidchisnall commented 5 years ago

With that patch to clang (I'll try to commit it tomorrow), the only remaining test failures that I see are due to a bug in LLVM's C personality function:

https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236905

Replacing this with the Objective-C personality function (which also works fine for C) makes the objc_msgSend test pass.

I have a few outstanding changes on your machine related to C++ exception interop, but it's getting late and I want to be awake when I tidy them up and commit them.

davidchisnall commented 5 years ago

FYI: This is the patch I have applied:

--- eh_personality.c    (revision 1248)
+++ eh_personality.c    (working copy)
@@ -481,6 +481,11 @@
    return _URC_INSTALL_CONTEXT;
 }

+BEGIN_PERSONALITY_FUNCTION(__gcc_personality_v0)
+   return internal_objc_personality(version, actions, exceptionClass,
+           exceptionObject, context, NO);
+}
+
 BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
    return internal_objc_personality(version, actions, exceptionClass,
            exceptionObject, context, NO);

It replaces the LLVM version of __gnu_objc_personality_v0 with the libobjc2 one. I've also disabled the very memory-intensive tests.

cyclaero commented 5 years ago

Perfect, Thank you very much. I will leave the system untouched and online.

davidchisnall commented 5 years ago

Feel free to disconnect it. I have done all of the testing that I need to do (exceptions and message sending now work correctly on FreeBSD/ARM - those are the only two architecture-specific bits of the runtime). I'll let you know if I need to test anything else.

davidchisnall commented 5 years ago

FYI: The clang fix is now upstream. It may be worth asking @brooksdavis to incorporate the fix (LLVM r357362) into the FreeBSD LLVM ports and @DimitryAndric to pull it into the base system version.