diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1034,6 +1034,23 @@ in.wordLiteralSection->finalizeContents(); } +static void referenceStubBinder() { + bool needsStubHelper = config->outputType == MH_DYLIB || + config->outputType == MH_EXECUTE || + config->outputType == MH_BUNDLE; + if (!needsStubHelper || !symtab->find("dyld_stub_binder")) + return; + + // dyld_stub_binder is used by dyld to resolve lazy bindings. This code here + // adds a opportunistic reference to dyld_stub_binder if it happens to exist. + // dyld_stub_binder is in libSystem.dylib, which is usually linked in. This + // isn't needed for correctness, but the presence of that symbol suppresses + // "no symbols" diagnostics from `nm`. + // StubHelperSection::setup() adds a reference and errors out if + // dyld_stub_binder doesn't exist in case it is actually needed. + symtab->addUndefined("dyld_stub_binder", /*file=*/nullptr, /*isWeak=*/false); +} + bool macho::link(ArrayRef argsArr, bool canExitEarly, raw_ostream &stdoutOS, raw_ostream &stderrOS) { lld::stdoutOS = &stdoutOS; @@ -1370,6 +1387,8 @@ treatUndefinedSymbol(*undefined, "-exported_symbol(s_list)"); } + referenceStubBinder(); + // FIXME: should terminate the link early based on errors encountered so // far? diff --git a/lld/test/MachO/dyld-stub-binder.s b/lld/test/MachO/dyld-stub-binder.s --- a/lld/test/MachO/dyld-stub-binder.s +++ b/lld/test/MachO/dyld-stub-binder.s @@ -8,6 +8,13 @@ # RUN: %lld -arch arm64 -dylib %t/foo.o -o %t/libfoo.dylib # RUN: llvm-nm -m %t/libfoo.dylib | FileCheck --check-prefix=NOSTUB %s +## Binaries that don't do lazy dynamic calls but are linked against +## libSystem.dylib get a reference to dyld_stub_binder even if it's +## not needed. +# RUN: %lld -arch arm64 -lSystem -dylib %t/foo.o -o %t/libfoo.dylib +# RUN: llvm-nm -m %t/libfoo.dylib | FileCheck --check-prefix=STUB %s + + ## Dylibs that do lazy dynamic calls do need dyld_stub_binder. # RUN: not %lld -arch arm64 -dylib %t/bar.o %t/libfoo.dylib \ # RUN: -o %t/libbar.dylib 2>&1 | FileCheck --check-prefix=MISSINGSTUB %s diff --git a/lld/test/MachO/lto-internalize.ll b/lld/test/MachO/lto-internalize.ll --- a/lld/test/MachO/lto-internalize.ll +++ b/lld/test/MachO/lto-internalize.ll @@ -33,6 +33,7 @@ ; SYMTAB-NEXT: g F __TEXT,__text _main ; SYMTAB-NEXT: g F __TEXT,__text _used_in_regular_obj ; SYMTAB-NEXT: g F __TEXT,__text __mh_execute_header +; SYMTAB-NEXT: *UND* dyld_stub_binder ; SYMTAB-EMPTY: ;--- test.s diff --git a/lld/test/MachO/stabs.s b/lld/test/MachO/stabs.s --- a/lld/test/MachO/stabs.s +++ b/lld/test/MachO/stabs.s @@ -105,6 +105,7 @@ # CHECK-DAG: ( SECT EXT) [[#%.2d,MORE_TEXT_ID + 1]] 0000 [[#FUN]] '_fun' # CHECK-DAG: ( SECT EXT) [[#%.2d,TEXT_ID + 1]] 0000 {{[0-9a-f]+}} '_no_debug' # CHECK-DAG: ( {{.*}}) {{[0-9]+}} 0010 {{[0-9a-f]+}} '__mh_execute_header' +# CHECK-DAG: ( {{.*}}) {{[0-9]+}} 0100 0000000000000000 'dyld_stub_binder' # CHECK-EMPTY: ## Check that we don't attempt to emit rebase opcodes for the debug sections