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 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 @@ -543,18 +543,13 @@ // 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. -// -// 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; +// documents in the same TBD file. // 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 +594,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 +656,7 @@ auto *c = reinterpret_cast(cmd); StringRef reexportPath = reinterpret_cast(c) + read32le(&c->dylib.name); - loadReexport(reexportPath, umbrella); + loadReexport(reexportPath, umbrella, nullptr); } } @@ -706,17 +703,16 @@ } } - bool isTopLevelTapi = false; - if (currentTopLevelTapi == nullptr) { - currentTopLevelTapi = &interface; - isTopLevelTapi = true; - } + const InterfaceFile *top_level = nullptr; + // If there is no top-level (meaning this tbd is the top-level) or if the + // current interface has no parent + if (interface.getParent() == nullptr) + top_level = &interface; + else + top_level = interface.getParent(); // Second+ level exporters. for (InterfaceFileRef intfRef : interface.reexportedLibraries()) - loadReexport(intfRef.getInstallName(), umbrella); - - if (isTopLevelTapi) - currentTopLevelTapi = nullptr; + loadReexport(intfRef.getInstallName(), umbrella, top_level); } 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,12 @@ +--- !tapi-tbd-v4 +tbd-version: 4 +archs: [ i386, x86_64 ] +uuids: [ 'i386: 00000000-0000-0000-0000-000000000000', 'x86_64: 00000000-0000-0000-0000-000000000001' ] +platform: ios +install-name: '/usr/lib/ReexportSystem.dylib' +reexported-libraries: + - archs: [i386, x86_64] + libraries: ['/usr/lib/libSystem.B.dylib'] +exports: + - archs: [ i386, x86_64 ] + symbols: [ __crashreporter_info__] 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 @@ -7,7 +7,7 @@ exports: - archs: [ i386, x86_64 ] re-exports: [ '/usr/lib/system/libcache.dylib' ] - symbols: [ __crashreporter_info__ ] + symbols: [ __crashreporter_info__] --- !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,14 @@ +# REQUIRES: x86 +# RUN: 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 -lSystem %t/test.o + +.text +.globl _main + +_main: + ret + +.data + .quad __crashreporter_info__ 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. @@ -404,6 +407,8 @@ bool operator!=(const InterfaceFile &O) const { return !(*this == O); } private: + InterfaceFile *parent = nullptr; + llvm::BumpPtrAllocator Allocator; StringRef copyString(StringRef String) { if (String.empty()) 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); }