From ba5087f13025a15662e164eb371fe0678258e03f Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Thu, 2 Jul 2020 00:02:09 -0400 Subject: [PATCH] ld64.lld: Add janky support for tbd files With this, a simple hello world links against libSystem.tbd and the old ld64.lld linker kind of works again with newer SDKs. The motivation here is to have an arm64 cross linker that's good enough to be able to run simple configure link checks on non-mac systems for generating config.h files. Once -flavor darwinnew can link arm64, we'll switch to that. --- lld/lib/ReaderWriter/MachO/File.h | 72 ++++++++++++++++++- .../MachO/MachOLinkingContext.cpp | 6 ++ .../MachO/MachONormalizedFileBinaryReader.cpp | 21 ++++++ .../MachO/MachONormalizedFileFromAtoms.cpp | 10 +-- .../MachO/MachONormalizedFileToAtoms.cpp | 22 +++--- .../Inputs/MacOSX.sdk/usr/lib/libSystem.tbd | 42 +++++++++++ lld/test/mach-o/stub-link.s | 21 ++++++ 7 files changed, 177 insertions(+), 17 deletions(-) create mode 100644 lld/test/mach-o/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd create mode 100644 lld/test/mach-o/stub-link.s diff --git a/lld/lib/ReaderWriter/MachO/File.h b/lld/lib/ReaderWriter/MachO/File.h index 072702973f81..a9a7faff89d2 100644 --- a/lld/lib/ReaderWriter/MachO/File.h +++ b/lld/lib/ReaderWriter/MachO/File.h @@ -17,6 +17,8 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/Format.h" +#include "llvm/TextAPI/MachO/InterfaceFile.h" +#include "llvm/TextAPI/MachO/TextAPIReader.h" #include namespace lld { @@ -322,7 +324,8 @@ public: void loadReExportedDylibs(FindDylib find) { for (ReExportedDylib &entry : _reExportedDylibs) { - entry.file = find(entry.path); + if (!entry.file) + entry.file = find(entry.path); } } @@ -339,7 +342,7 @@ public: return std::error_code(); } -private: +protected: OwningAtomPtr exports(StringRef name, StringRef installName) const { // First, check if requested symbol is directly implemented by this dylib. @@ -373,6 +376,7 @@ private: struct ReExportedDylib { ReExportedDylib(StringRef p) : path(p), file(nullptr) { } + ReExportedDylib(StringRef p, MachODylibFile *file) : path(p), file(file) { } StringRef path; MachODylibFile *file; }; @@ -393,6 +397,70 @@ private: mutable std::unordered_map _nameToAtom; }; +class TAPIFile : public MachODylibFile { +public: + + TAPIFile(std::unique_ptr mb, MachOLinkingContext *ctx) + : MachODylibFile(std::move(mb), ctx) {} + + std::error_code doParse() override { + + llvm::Expected> result = + llvm::MachO::TextAPIReader::get(*_mb); + if (!result) + return std::make_error_code(std::errc::invalid_argument); + + std::unique_ptr interface{std::move(*result)}; + return loadFromInterface(*interface); + } + +private: + std::error_code loadFromInterface(llvm::MachO::InterfaceFile &interface) { + llvm::MachO::Architecture arch; + switch(_ctx->arch()) { + case MachOLinkingContext::arch_x86: + arch = llvm::MachO::AK_i386; + break; + case MachOLinkingContext::arch_x86_64: + arch = llvm::MachO::AK_x86_64; + break; + case MachOLinkingContext::arch_arm64: + arch = llvm::MachO::AK_arm64; + break; + default: + return std::make_error_code(std::errc::invalid_argument); + } + + setInstallName(interface.getInstallName().copy(allocator())); + // TODO(compnerd) filter out symbols based on the target platform + for (const auto symbol : interface.symbols()) + if (symbol->getArchitectures().has(arch)) + addExportedSymbol(symbol->getName(), symbol->isWeakDefined(), true); + + for (const llvm::MachO::InterfaceFileRef &reexport : + interface.reexportedLibraries()) + addReExportedDylib(reexport.getInstallName().copy(allocator())); + + for (const auto& document : interface.documents()) { + for (auto& reexport : _reExportedDylibs) { + if (reexport.path != document->getInstallName()) + continue; + assert(!reexport.file); + _ownedFiles.push_back(std::make_unique( + MemoryBuffer::getMemBuffer("", _mb->getBufferIdentifier()), _ctx)); + reexport.file = _ownedFiles.back().get(); + std::error_code err = _ownedFiles.back()->loadFromInterface(*document); + if (!err) + return err; + } + } + + return std::error_code(); + } + + std::vector> _ownedFiles; +}; + } // end namespace mach_o } // end namespace lld diff --git a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp index 6fe9cde544d6..acd919e4d411 100644 --- a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -540,6 +540,12 @@ MachOLinkingContext::searchDirForLibrary(StringRef path, return llvm::None; } + // Search for stub library + fullPath.assign(path); + llvm::sys::path::append(fullPath, Twine("lib") + libName + ".tbd"); + if (fileExists(fullPath)) + return fullPath.str().copy(_allocator); + // Search for dynamic library fullPath.assign(path); llvm::sys::path::append(fullPath, Twine("lib") + libName + ".dylib"); diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp index 963f1227fa44..87601ca1be8b 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp @@ -576,6 +576,26 @@ private: MachOLinkingContext &_ctx; }; +class MachOTAPIReader : public Reader { +public: + MachOTAPIReader(MachOLinkingContext &ctx) : _ctx(ctx) {} + + bool canParse(file_magic magic, MemoryBufferRef mb) const override { + return magic == file_magic::tapi_file; + } + + ErrorOr> + loadFile(std::unique_ptr mb, + const Registry ®istry) const override { + std::unique_ptr ret = + std::make_unique(std::move(mb), &_ctx); + return std::move(ret); + } + +private: + MachOLinkingContext &_ctx; +}; + } // namespace normalized } // namespace mach_o @@ -583,6 +603,7 @@ void Registry::addSupportMachOObjects(MachOLinkingContext &ctx) { MachOLinkingContext::Arch arch = ctx.arch(); add(std::unique_ptr(new mach_o::normalized::MachOObjectReader(ctx))); add(std::unique_ptr(new mach_o::normalized::MachODylibReader(ctx))); + add(std::unique_ptr(new mach_o::normalized::MachOTAPIReader(ctx))); addKindTable(Reference::KindNamespace::mach_o, ctx.archHandler().kindArch(), ctx.archHandler().kindStrings()); add(std::unique_ptr( diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp index 55dcad955e85..42ac711bc9dc 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp @@ -1037,7 +1037,7 @@ llvm::Error Util::addSymbols(const lld::File &atomFile, // Add all stabs. for (auto &stab : _stabs) { - Symbol sym; + lld::mach_o::normalized::Symbol sym; sym.type = static_cast(stab.type); sym.scope = 0; sym.sect = stab.other; @@ -1066,7 +1066,7 @@ llvm::Error Util::addSymbols(const lld::File &atomFile, AtomAndIndex ai = { atom, sect->finalSectionIndex, symbolScope }; globals.push_back(ai); } else { - Symbol sym; + lld::mach_o::normalized::Symbol sym; sym.name = atom->name(); sym.type = N_SECT; sym.scope = symbolScope; @@ -1082,7 +1082,7 @@ llvm::Error Util::addSymbols(const lld::File &atomFile, char tmpName[16]; sprintf(tmpName, "L%04u", tempNum++); StringRef tempRef(tmpName); - Symbol sym; + lld::mach_o::normalized::Symbol sym; sym.name = tempRef.copy(file.ownedAllocations); sym.type = N_SECT; sym.scope = 0; @@ -1099,7 +1099,7 @@ llvm::Error Util::addSymbols(const lld::File &atomFile, std::sort(globals.begin(), globals.end(), AtomSorter()); const uint32_t globalStartIndex = file.localSymbols.size(); for (AtomAndIndex &ai : globals) { - Symbol sym; + lld::mach_o::normalized::Symbol sym; sym.name = ai.atom->name(); sym.type = N_SECT; sym.scope = ai.scope; @@ -1124,7 +1124,7 @@ llvm::Error Util::addSymbols(const lld::File &atomFile, std::sort(undefs.begin(), undefs.end(), AtomSorter()); const uint32_t start = file.globalSymbols.size() + file.localSymbols.size(); for (AtomAndIndex &ai : undefs) { - Symbol sym; + lld::mach_o::normalized::Symbol sym; uint16_t desc = 0; if (!rMode) { uint8_t ordinal = 0; diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index 80a1bf00a70d..0a59e24c47a8 100644 --- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -223,10 +223,11 @@ Atom::Scope atomScope(uint8_t scope) { llvm_unreachable("unknown scope value!"); } -void appendSymbolsInSection(const std::vector &inSymbols, - uint32_t sectionIndex, - SmallVector &outSyms) { - for (const Symbol &sym : inSymbols) { +void appendSymbolsInSection( + const std::vector &inSymbols, + uint32_t sectionIndex, + SmallVector &outSyms) { + for (const lld::mach_o::normalized::Symbol &sym : inSymbols) { // Only look at definition symbols. if ((sym.type & N_TYPE) != N_SECT) continue; @@ -286,13 +287,14 @@ llvm::Error processSymboledSection(DefinedAtom::ContentType atomType, } // Find all symbols in this section. - SmallVector symbols; + SmallVector symbols; appendSymbolsInSection(normalizedFile.globalSymbols, sectIndex, symbols); appendSymbolsInSection(normalizedFile.localSymbols, sectIndex, symbols); // Sort symbols. std::sort(symbols.begin(), symbols.end(), - [](const Symbol *lhs, const Symbol *rhs) -> bool { + [](const lld::mach_o::normalized::Symbol *lhs, + const lld::mach_o::normalized::Symbol *rhs) -> bool { if (lhs == rhs) return false; // First by address. @@ -300,7 +302,7 @@ llvm::Error processSymboledSection(DefinedAtom::ContentType atomType, uint64_t rhsAddr = rhs->value; if (lhsAddr != rhsAddr) return lhsAddr < rhsAddr; - // If same address, one is an alias so sort by scope. + // If same address, one is an alias so sort by scope. Atom::Scope lScope = atomScope(lhs->scope); Atom::Scope rScope = atomScope(rhs->scope); if (lScope != rScope) @@ -339,8 +341,8 @@ llvm::Error processSymboledSection(DefinedAtom::ContentType atomType, scatterable, copyRefs); } - const Symbol *lastSym = nullptr; - for (const Symbol *sym : symbols) { + const lld::mach_o::normalized::Symbol *lastSym = nullptr; + for (const lld::mach_o::normalized::Symbol *sym : symbols) { if (lastSym != nullptr) { // Ignore any assembler added "ltmpNNN" symbol at start of section // if there is another symbol at the start. @@ -550,7 +552,7 @@ llvm::Error convertRelocs(const Section §ion, auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result) -> llvm::Error { // Find symbol from index. - const Symbol *sym = nullptr; + const lld::mach_o::normalized::Symbol *sym = nullptr; uint32_t numStabs = normalizedFile.stabsSymbols.size(); uint32_t numLocal = normalizedFile.localSymbols.size(); uint32_t numGlobal = normalizedFile.globalSymbols.size(); diff --git a/lld/test/mach-o/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd b/lld/test/mach-o/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd new file mode 100644 index 000000000000..1a90cff2978b --- /dev/null +++ b/lld/test/mach-o/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd @@ -0,0 +1,42 @@ +--- !tapi-tbd-v3 +archs: [ x86_64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000000' ] +platform: macosx +install-name: '/usr/lib/libSystem.B.dylib' +current-version: 0001.001.1 +exports: + - archs: [ 'x86_64' ] + re-exports: [ '/usr/lib/system/libdyld.dylib', + '/usr/lib/system/libsystem_c.dylib', + '/usr/lib/system/libsystem_m.dylib' ] +--- !tapi-tbd-v3 +archs: [ x86_64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000001' ] +platform: macosx +install-name: '/usr/lib/libdyld.dylib' +current-version: 0001.001.1 +parent-umbrella: System +exports: + - archs: [ 'x86_64' ] + symbols: [ dyld_stub_binder ] +--- !tapi-tbd-v3 +archs: [ x86_64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000002' ] +platform: macosx +install-name: '/usr/lib/libsystem_c.dylib' +current-version: 0001.001.1 +parent-umbrella: System +exports: + - archs: [ 'x86_64' ] + symbols: [ ] +--- !tapi-tbd-v3 +archs: [ x86_64 ] +uuids: [ 'x86_64: 00000000-0000-0000-0000-000000000003' ] +platform: macosx +install-name: '/usr/lib/libsystem_m.dylib' +current-version: 0001.001.1 +parent-umbrella: System +exports: + - archs: [ 'x86_64' ] + symbols: [ ___nan ] +... diff --git a/lld/test/mach-o/stub-link.s b/lld/test/mach-o/stub-link.s new file mode 100644 index 000000000000..fb12b76f44d9 --- /dev/null +++ b/lld/test/mach-o/stub-link.s @@ -0,0 +1,21 @@ +# REQUIRES: x86 + +# RUN: mkdir -p %t +# +# RUN: llvm-mc -filetype obj -triple x86_64-apple-darwin %s -o %t/test.o +# RUN: ld64.lld -o %t/test -Z -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem %t/test.o +# +# RUN: llvm-objdump --bind --no-show-raw-insn -d -r %t/test | FileCheck %s + +# CHECK: Disassembly of section __TEXT,__text: +# CHECK: movq {{.*}} # [[ADDR:[0-9a-f]+]] + +# CHECK: Bind table: +# CHECK: __DATA __got 0x[[ADDR]] pointer 0 libSystem ___nan + +.section __TEXT,__text +.global _main + +_main: + movq ___nan@GOTPCREL(%rip), %rax + ret