Xcode14 Linker assert: ld: Assertion failed: (dylib != NULL), function classicOrdinalForProxy, file LinkEditClassic.hpp, line 495

Originator:lewurm
Number:rdar://FB11544896 Date Originated:09/19/2022
Status:Closed Resolved:yes
Product:Xcode Product Version:Xcode 14.0 Build version 14A309
Classification: Reproducible:yes
 
Please see https://gist.github.com/lewurm/48deb2ce67d6c93cff66965d6d770302

Copy of the README.md here:

Reproducer for triggering the following assert with Xcode14.

```sh
$ xcodebuild -version
Xcode 14.0
Build version 14A309

$ make hello_with_objc_selector_stubs
ld -o hello_with_objc_selector_stubs  -syslibroot /Applications/Xcode14.1-beta1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -lSystem -arch arm64 -platform_version macos 12.0.0 13.0  -U ___darwin_check_fd_set_overflow -ldl -lpthread -framework Foundation -lz /Applications/Xcode14-beta5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.0/lib/darwin/libclang_rt.osx.a libdarwin_withstubs.a helloworld.o liblibchelper.a libnet.a libnio.a libjava.a libfdlibm.a libzip.a libjvm.a
0  0x104e641a0  __assert_rtn + 140
1  0x104e6d2ec  ld::tool::SymbolTableAtom<arm64>::classicOrdinalForProxy(ld::Atom const*) (.cold.2) + 0
2  0x104d75598  ld::tool::LocalRelocationsAtom<arm64_32>::~LocalRelocationsAtom() + 0
3  0x104d74ab8  ld::tool::SymbolTableAtom<arm64>::addImport(ld::Atom const*, ld::tool::StringPoolAtom*) + 204
4  0x104d74150  ld::tool::SymbolTableAtom<arm64>::encode() + 420
5  0x104d60c18  ___ZN2ld4tool10OutputFile20buildLINKEDITContentERNS_8InternalE_block_invoke_3 + 36
6  0x1825325f0  _dispatch_call_block_and_release + 32
7  0x1825341b4  _dispatch_client_callout + 20
8  0x182545b14  _dispatch_root_queue_drain + 952
9  0x182546104  _dispatch_worker_thread2 + 164
10  0x1826f4324  _pthread_wqthread + 228
A linker snapshot was created at:
        /tmp/hello_with_objc_selector_stubs-2022-09-19-164512.ld-snapshot
ld: Assertion failed: (dylib != NULL), function classicOrdinalForProxy, file LinkEditClassic.hpp, line 495.
make: *** [hello_with_objc_selector_stubs] Error 1
```

I noticed that adding `-undefined dynamic_lookup` helps to avoid the assert:
```sh
$ LDFLAGS='-undefined dynamic_lookup' make hello_with_objc_selector_stubs
ld -o hello_with_objc_selector_stubs  -undefined dynamic_lookup -syslibroot /Applications/Xcode14.1-beta1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -lSystem -arch arm64 -platform_version macos 12.0.0 13.0  -U ___darwin_check_fd_set_overflow -ldl -lpthread -framework Foundation -lz /Applications/Xcode14-beta5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.0/lib/darwin/libclang_rt.osx.a libdarwin_withstubs.a helloworld.o liblibchelper.a libnet.a libnio.a libjava.a libfdlibm.a libzip.a libjvm.a
ld: warning: -undefined dynamic_lookup may not work with chained fixups
```

However, trying to execute the final binary it fails with:
```sh
$ ./hello_with_objc_selector_stubs
dyld[72323]: symbol not found in flat namespace (_objc_msgSend$UTF8String)
zsh: abort      ./hello_with_objc_selector_stubs
```

Which triggered a memory from a [WWDC22 talk](https://developer.apple.com/videos/play/wwdc2022/110363/) (section `Message send`).

The origin is this static library:
```sh
$ nm libdarwin_withstubs.a

libdarwin_withstubs.a(foundation.o):
00000000000000c8 s _OBJC_CLASSLIST_REFERENCES_$_
00000000000000d0 s _OBJC_CLASSLIST_REFERENCES_$_.3
                 U _OBJC_CLASS_$_NSDictionary
                 U _OBJC_CLASS_$_NSProcessInfo
                 U ___CFConstantStringClassReference
                 U _objc_msgSend$UTF8String
                 U _objc_msgSend$dictionaryWithContentsOfFile:
                 U _objc_msgSend$objectForKey:
                 U _objc_msgSend$operatingSystemVersion
                 U _objc_msgSend$processInfo
0000000000000000 T _operatingSystemVersion
                 U _strdup
[...]
```

So I compiled `foundation.o` with `-fno-objc-msgsend-selector-stubs`, the result is in `libdarwin_nostubs.a`.

```sh
$ make hello_without_objc_selector_stubs
ld -o hello_without_objc_selector_stubs   -syslibroot /Applications/Xcode14.1-beta1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -lSystem -arch arm64 -platform_version macos 12.0.0 13.0  -U ___darwin_check_fd_set_overflow -ldl -lpthread -framework Foundation -lz /Applications/Xcode14-beta5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.0/lib/darwin/libclang_rt.osx.a libdarwin_nostubs.a helloworld.o liblibchelper.a libnet.a libnio.a libjava.a libfdlibm.a libzip.a libjvm.a
$ ./hello_without_objc_selector_stubs
null
```

which works as expected.

By the way, sorry I didn't manage to come up with a source-only reproducer.

Also, please push a newer revision on GitHub: https://github.com/apple-opensource/ld64/issues/2

Comments

Thank you! Adding PURE_INSTRUCTIONS indeed fixed the issue for us.

PS: Please update https://github.com/apple-opensource/ld64 :-)

Engineering has provided the following information regarding this issue:

The problem is with the GraalVM object file helloworld.o, __TEXT,__text section should be marked with PURE_INSTRUCTIONS attribute, but it’s not:

$ otool -lv helloworld.o

attributes SOME_INSTRUCTIONS EXT_RELOC

You can workaround the problem by compiling an empty source file with clang, e.g., like this:

$ echo "" > dummy.c

$ clang dummy.c -o dummy.o -c -target arm64-apple-macosx12.0

And listing it as the first object file in linker invocation, so this works:

hello_with_objc_selector_stubs: helloworld.o Makefile

$(LD) -o $@ $(LDFLAGS) dummy.o libdarwin_withstubs.a helloworld.o $(LIBS)

The linker assertion is only a side effect of the missing attribute, so on our side we can improve the diagnostics, but you can already proceed with the workaround.


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!