diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp --- a/lld/MachO/DriverUtils.cpp +++ b/lld/MachO/DriverUtils.cpp @@ -234,7 +234,7 @@ // in previous block for why this means we must copy `file` here. newFile = file; if (newFile->exportingFile) - newFile->parseLoadCommands(mbref, umbrella); + newFile->parseLoadCommands(mbref); } return newFile; } diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h --- a/lld/MachO/InputFiles.h +++ b/lld/MachO/InputFiles.h @@ -144,13 +144,14 @@ // the root dylib to ensure symbols in the child library are correctly bound // to the root. On the other hand, if a dylib is being directly loaded // (through an -lfoo flag), then `umbrella` should be a nullptr. - void parseLoadCommands(MemoryBufferRef mb, DylibFile *umbrella); + void parseLoadCommands(MemoryBufferRef mb); void parseReexports(const llvm::MachO::InterfaceFile &interface); static bool classof(const InputFile *f) { return f->kind() == DylibKind; } StringRef dylibName; DylibFile *exportingFile = nullptr; + DylibFile *umbrella; uint32_t compatibilityVersion = 0; uint32_t currentVersion = 0; int64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -766,8 +766,11 @@ for (InterfaceFile &child : make_pointee_range(currentTopLevelTapi->documents())) { assert(child.documents().empty()); - if (path == child.getInstallName()) - return make(child, umbrella); + if (path == child.getInstallName()) { + auto file = make(child, umbrella); + file->parseReexports(child); + return file; + } } } @@ -813,6 +816,7 @@ assert(!isBundleLoader || !umbrella); if (umbrella == nullptr) umbrella = this; + this->umbrella = umbrella; auto *buf = reinterpret_cast(mb.getBufferStart()); auto *hdr = reinterpret_cast(mb.getBufferStart()); @@ -839,7 +843,7 @@ return; // Initialize symbols. - exportingFile = isImplicitlyLinked(dylibName) ? this : umbrella; + exportingFile = isImplicitlyLinked(dylibName) ? this : this->umbrella; if (const load_command *cmd = findCommand(hdr, LC_DYLD_INFO_ONLY)) { auto *c = reinterpret_cast(cmd); parseTrie(buf + c->export_off, c->export_size, @@ -855,7 +859,7 @@ } } -void DylibFile::parseLoadCommands(MemoryBufferRef mb, DylibFile *umbrella) { +void DylibFile::parseLoadCommands(MemoryBufferRef mb) { auto *hdr = reinterpret_cast(mb.getBufferStart()); const uint8_t *p = reinterpret_cast(mb.getBufferStart()) + target->headerSize; @@ -902,6 +906,7 @@ if (umbrella == nullptr) umbrella = this; + this->umbrella = umbrella; dylibName = saver.save(interface.getInstallName()); compatibilityVersion = interface.getCompatibilityVersion().rawValue(); @@ -949,7 +954,7 @@ } } -void DylibFile::parseReexports(const llvm::MachO::InterfaceFile &interface) { +void DylibFile::parseReexports(const InterfaceFile &interface) { const InterfaceFile *topLevel = interface.getParent() == nullptr ? &interface : interface.getParent(); for (InterfaceFileRef intfRef : interface.reexportedLibraries()) { diff --git a/lld/test/MachO/tapi-link.s b/lld/test/MachO/tapi-link.s --- a/lld/test/MachO/tapi-link.s +++ b/lld/test/MachO/tapi-link.s @@ -1,16 +1,16 @@ # REQUIRES: x86 -# RUN: mkdir -p %t -# -# RUN: llvm-mc -filetype obj -triple x86_64-apple-darwin %s -o %t/test.o +# RUN: split-file %s %t --no-leading-lines -# RUN: %lld -o %t/test -lSystem -lc++ -framework CoreFoundation %t/test.o +# RUN: llvm-mc -filetype obj -triple x86_64-apple-darwin %t/test.s -o %t/test.o + +# RUN: %lld -o %t/test -lSystem -lc++ -framework CoreFoundation %t/libNested.tbd %t/test.o # RUN: llvm-objdump --bind --no-show-raw-insn -d -r %t/test | FileCheck %s ## libReexportSystem.tbd tests that we can reference symbols from a dylib, ## re-exported by a top-level tapi document, which itself is re-exported by ## another top-level tapi document. -# RUN: %lld -o %t/with-reexport %S/Inputs/libReexportSystem.tbd -lc++ -framework CoreFoundation %t/test.o +# RUN: %lld -o %t/with-reexport %S/Inputs/libReexportSystem.tbd -lc++ -framework CoreFoundation %t/libNested.tbd %t/test.o # RUN: llvm-objdump --bind --no-show-raw-insn -d -r %t/with-reexport | FileCheck %s # CHECK: Disassembly of section __TEXT,__text: @@ -23,6 +23,7 @@ # CHECK-DAG: __DATA __data {{.*}} pointer 0 CoreFoundation _OBJC_IVAR_$_NSConstantArray._count # CHECK-DAG: __DATA __data {{.*}} pointer 0 CoreFoundation _OBJC_EHTYPE_$_NSException # CHECK-DAG: __DATA __data {{.*}} pointer 0 libc++abi ___gxx_personality_v0 +# CHECK-DAG: __DATA __data {{.*}} pointer 0 libNested3 _deeply_nested # RUN: llvm-objdump --macho --all-headers %t/test | \ # RUN: FileCheck --check-prefix=LOAD %s @@ -44,6 +45,7 @@ # LOAD-REEXPORT-NEXT: current version 1.0.0 # LOAD-REEXPORT-NEXT: compatibility version +#--- test.s .section __TEXT,__text .global _main @@ -57,9 +59,39 @@ .quad _OBJC_METACLASS_$_NSObject .quad _OBJC_IVAR_$_NSConstantArray._count .quad _OBJC_EHTYPE_$_NSException + .quad _deeply_nested ## This symbol is defined in libc++abi.tbd, but we are linking test.o against ## libc++.tbd (which re-exports libc++abi). Linking against this symbol verifies ## that .tbd file re-exports can refer not just to TAPI documents within the ## same .tbd file, but to other on-disk files as well. .quad ___gxx_personality_v0 + +## This tests that we can locate a symbol re-exported by a child of a TAPI +## document. +#--- libNested.tbd +--- !tapi-tbd-v3 +archs: [ x86_64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000000' ] +platform: macosx +install-name: '/usr/lib/libNested.dylib' +exports: + - archs: [ x86_64 ] + re-exports: [ '/usr/lib/libNested2.dylib' ] +--- !tapi-tbd-v3 +archs: [ x86_64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000001' ] +platform: macosx +install-name: '/usr/lib/libNested2.dylib' +exports: + - archs: [ x86_64 ] + re-exports: [ '/usr/lib/libNested3.dylib' ] +--- !tapi-tbd-v3 +archs: [ x86_64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000002' ] +platform: macosx +install-name: '/usr/lib/libNested3.dylib' +exports: + - archs: [ x86_64 ] + symbols: [ _deeply_nested ] +...