diff --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h --- a/lld/MachO/Driver.h +++ b/lld/MachO/Driver.h @@ -15,6 +15,12 @@ #include "llvm/Option/OptTable.h" #include "llvm/Support/MemoryBuffer.h" +namespace llvm { +namespace MachO { +class InterfaceFile; +} // namespace MachO +} // namespace llvm + namespace lld { namespace macho { diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -541,20 +541,16 @@ // TBD files are parsed into a series of TAPI documents (InterfaceFiles), with // the first document storing child pointers to the rest of them. When we are -// processing a given TBD file, we store that top-level document here. When -// processing re-exports, we search its children for potentially matching -// documents in the same TBD file. Note that the children themselves don't -// point to further documents, i.e. this is a two-level tree. +// processing a given TBD file, we store that top-level document in +// currentTopLevelTapi. When processing re-exports, we search its children for +// potentially matching documents in the same TBD file. Note that the children +// themselves don't point to further documents, i.e. this is a two-level tree. // -// ld64 allows a TAPI re-export to reference documents nested within other TBD -// files, but that seems like a strange design, so this is an intentional -// deviation. -const InterfaceFile *currentTopLevelTapi = nullptr; - // Re-exports can either refer to on-disk files, or to documents within .tbd // files. -static Optional loadReexportHelper(StringRef path, - DylibFile *umbrella) { +static Optional +loadReexportHelper(StringRef path, DylibFile *umbrella, + const InterfaceFile *currentTopLevelTapi) { if (path::is_absolute(path, path::Style::posix)) for (StringRef root : config->systemLibraryRoots) if (Optional dylibPath = @@ -599,8 +595,10 @@ return false; } -void loadReexport(StringRef path, DylibFile *umbrella) { - Optional reexport = loadReexportHelper(path, umbrella); +void loadReexport(StringRef path, DylibFile *umbrella, + const InterfaceFile *currentTopLevelTapi) { + Optional reexport = + loadReexportHelper(path, umbrella, currentTopLevelTapi); if (reexport && isImplicitlyLinked(path)) inputFiles.insert(*reexport); } @@ -659,7 +657,7 @@ auto *c = reinterpret_cast(cmd); StringRef reexportPath = reinterpret_cast(c) + read32le(&c->dylib.name); - loadReexport(reexportPath, umbrella); + loadReexport(reexportPath, umbrella, nullptr); } } @@ -706,17 +704,11 @@ } } - bool isTopLevelTapi = false; - if (currentTopLevelTapi == nullptr) { - currentTopLevelTapi = &interface; - isTopLevelTapi = true; - } + const InterfaceFile *topLevel = + interface.getParent() == nullptr ? &interface : interface.getParent(); for (InterfaceFileRef intfRef : interface.reexportedLibraries()) - loadReexport(intfRef.getInstallName(), umbrella); - - if (isTopLevelTapi) - currentTopLevelTapi = nullptr; + loadReexport(intfRef.getInstallName(), umbrella, topLevel); } ArchiveFile::ArchiveFile(std::unique_ptr &&f) diff --git a/lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libReexportSystem.tbd b/lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libReexportSystem.tbd new file mode 100644 --- /dev/null +++ b/lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libReexportSystem.tbd @@ -0,0 +1,10 @@ +--- !tapi-tbd-v3 +archs: [ i386, x86_64 ] +uuids: [ 'i386: 00000000-0000-0000-0000-000000000000', 'x86_64: 00000000-0000-0000-0000-000000000001' ] +platform: ios +install-name: '/usr/lib/libReexportSystem.dylib' +exports: + - archs: [ i386, x86_64 ] + re-exports: [ '/usr/lib/libSystem' ] + symbols: [ __crashreporter_info__, _cache_create ] + diff --git a/lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libSystem.tbd b/lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libSystem.tbd --- a/lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libSystem.tbd +++ b/lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libSystem.tbd @@ -6,8 +6,8 @@ current-version: 1281 exports: - archs: [ i386, x86_64 ] - re-exports: [ '/usr/lib/system/libcache.dylib' ] - symbols: [ __crashreporter_info__ ] + re-exports: [ '/usr/lib/system/libcache.dylib', ] + symbols: [ __crashreporter_info__, _cache_create ] --- !tapi-tbd-v3 archs: [ i386, x86_64 ] uuids: [ 'i386: 00000000-0000-0000-0000-000000000002', 'x86_64: 00000000-0000-0000-0000-000000000003' ] diff --git a/lld/test/MachO/reexport-nested-lib.s b/lld/test/MachO/reexport-nested-lib.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/reexport-nested-lib.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 +# +# This 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: rm -rf %t; mkdir -p %t +# RUN: llvm-mc -filetype obj -triple x86_64-apple-darwin %s -o %t/test.o +# RUN: %lld -o %t/test -syslibroot %S/Inputs/iPhoneSimulator.sdk -lReexportSystem %t/test.o +# RUN: llvm-objdump %t/test --macho --bind %t/test | FileCheck %s + +# CHECK: segment section address type addend dylib symbol +# CHECK: __DATA __data 0x{{[0-9a-f]*}} pointer 0 libReexportSystem __crashreporter_info__ +# CHECK: __DATA __data 0x{{[0-9a-f]*}} pointer 0 libReexportSystem _cache_create + +.text +.globl _main + +_main: + ret + +.data +// This symbol is from libSystem, which is re-exported by libReexportSystem. +// Reference it here to verify that it is visible. +.quad __crashreporter_info__ + +// This symbol is from reexported fake_lib.dylib. +.quad _cache_create diff --git a/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h b/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h --- a/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h +++ b/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h @@ -338,6 +338,9 @@ ///\param Document The library to inline with top level library. void addDocument(std::shared_ptr &&Document); + /// Returns the pointer to parent document if exists or nullptr otherwise. + InterfaceFile *getParent() const { return Parent; } + /// Get the list of inlined libraries. /// /// \return Returns a list of the inlined frameworks. @@ -431,6 +434,7 @@ std::vector> Documents; std::vector> UUIDs; SymbolMapType Symbols; + InterfaceFile *Parent = nullptr; }; template diff --git a/llvm/lib/TextAPI/MachO/InterfaceFile.cpp b/llvm/lib/TextAPI/MachO/InterfaceFile.cpp --- a/llvm/lib/TextAPI/MachO/InterfaceFile.cpp +++ b/llvm/lib/TextAPI/MachO/InterfaceFile.cpp @@ -124,6 +124,7 @@ const std::shared_ptr &RHS) { return LHS->InstallName < RHS->InstallName; }); + Document->Parent = this; Documents.insert(Pos, Document); }