diff --git a/.gitignore b/.gitignore index c1615e8..3311250 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,5 @@ /lld-10.0.0rc6.src.tar.xz.sig /lld-10.0.0.src.tar.xz /lld-10.0.0.src.tar.xz.sig +/lld-11.0.0rc1.src.tar.xz +/lld-11.0.0rc1.src.tar.xz.sig diff --git a/0001-Revert-lld-Initial-commit-for-new-Mach-O-backend.patch b/0001-Revert-lld-Initial-commit-for-new-Mach-O-backend.patch new file mode 100644 index 0000000..597ebb9 --- /dev/null +++ b/0001-Revert-lld-Initial-commit-for-new-Mach-O-backend.patch @@ -0,0 +1,7986 @@ +From c81a0aa7794dab5420165e47eebd6337b0da5891 Mon Sep 17 00:00:00 2001 +From: Tom Stellard +Date: Mon, 10 Aug 2020 16:44:53 -0700 +Subject: [PATCH] Revert "[lld] Initial commit for new Mach-O backend" + +This reverts commit 03f43b3aca363e16c45d8733400fd0083b1af4d8. +--- + lld/CMakeLists.txt | 1 - + lld/MachO/Arch/X86_64.cpp | 286 ---- + lld/MachO/CMakeLists.txt | 36 - + lld/MachO/Config.h | 57 - + lld/MachO/Driver.cpp | 451 ------ + lld/MachO/Driver.h | 36 - + lld/MachO/ExportTrie.cpp | 283 ---- + lld/MachO/ExportTrie.h | 47 - + lld/MachO/InputFiles.cpp | 433 ------ + lld/MachO/InputFiles.h | 121 -- + lld/MachO/InputSection.cpp | 48 - + lld/MachO/InputSection.h | 74 - + lld/MachO/MachOStructs.h | 36 - + lld/MachO/MergedOutputSection.cpp | 74 - + lld/MachO/MergedOutputSection.h | 56 - + lld/MachO/Options.td | 1297 ----------------- + lld/MachO/OutputSection.cpp | 18 - + lld/MachO/OutputSection.h | 74 - + lld/MachO/OutputSegment.cpp | 67 - + lld/MachO/OutputSegment.h | 62 - + lld/MachO/SymbolTable.cpp | 87 -- + lld/MachO/SymbolTable.h | 50 - + lld/MachO/Symbols.cpp | 23 - + lld/MachO/Symbols.h | 138 -- + lld/MachO/SyntheticSections.cpp | 409 ------ + lld/MachO/SyntheticSections.h | 290 ---- + lld/MachO/Target.cpp | 14 - + lld/MachO/Target.h | 75 - + lld/MachO/Writer.cpp | 542 ------- + lld/MachO/Writer.h | 31 - + lld/include/lld/Common/Driver.h | 5 - + .../Inputs/MacOSX.sdk/usr/lib/libSystem.tbd | 42 - + .../iPhoneSimulator.sdk/usr/lib/libSystem.tbd | 23 - + lld/test/MachO/Inputs/libfunction.s | 6 - + lld/test/MachO/Inputs/libgoodbye.s | 14 - + lld/test/MachO/Inputs/libhello.s | 17 - + lld/test/MachO/arch.s | 11 - + lld/test/MachO/archive.s | 35 - + lld/test/MachO/bss.s | 59 - + lld/test/MachO/dylib.s | 35 - + lld/test/MachO/dylink-lazy.s | 62 - + lld/test/MachO/dylink.s | 69 - + lld/test/MachO/entry-symbol.s | 28 - + lld/test/MachO/export-trie.s | 44 - + lld/test/MachO/fat-arch.s | 16 - + .../MachO/invalid/alignment-too-large.yaml | 58 - + lld/test/MachO/invalid/archive-no-index.s | 17 - + lld/test/MachO/invalid/bad-archive.s | 11 - + lld/test/MachO/invalid/duplicate-symbol.s | 12 - + lld/test/MachO/invalid/invalid-executable.s | 11 - + lld/test/MachO/invalid/invalid-fat-narch.s | 12 - + lld/test/MachO/invalid/invalid-fat-offset.s | 22 - + .../invalid/invalid-relocation-length.yaml | 99 -- + .../invalid/invalid-relocation-pcrel.yaml | 99 -- + lld/test/MachO/invalid/missing-dylib.s | 5 - + lld/test/MachO/invalid/no-id-dylink.yaml | 166 --- + lld/test/MachO/invalid/no-such-file.s | 4 - + .../MachO/invalid/order-file-bad-arch.test | 9 - + .../MachO/invalid/order-file-bad-objfile.test | 10 - + .../MachO/invalid/reserved-section-name.s | 14 - + lld/test/MachO/invalid/stub-link.s | 15 - + lld/test/MachO/invalid/undefined-symbol.s | 11 - + lld/test/MachO/link-search-order.s | 43 - + lld/test/MachO/load-commands.s | 22 - + lld/test/MachO/local-got.s | 58 - + lld/test/MachO/no-exports-dylib.s | 6 - + lld/test/MachO/order-file.s | 131 -- + lld/test/MachO/platform-version.test | 17 - + lld/test/MachO/relocations.s | 66 - + lld/test/MachO/resolution.s | 44 - + lld/test/MachO/search-paths-darwin.test | 20 - + lld/test/MachO/search-paths.test | 15 - + lld/test/MachO/section-headers.s | 46 - + lld/test/MachO/section-merge.s | 26 - + lld/test/MachO/segments.s | 53 - + lld/test/MachO/silent-ignore.test | 9 - + lld/test/MachO/static-link.s | 30 - + lld/test/MachO/stub-link.s | 21 - + lld/test/MachO/sub-library.s | 74 - + lld/test/MachO/subsections-section-relocs.s | 47 - + lld/test/MachO/subsections-symbol-relocs.s | 55 - + lld/test/MachO/symbol-order.s | 46 - + lld/test/MachO/symtab.s | 54 - + lld/test/MachO/x86-64-reloc-signed.s | 64 - + lld/test/MachO/x86-64-reloc-unsigned.s | 31 - + lld/tools/lld/CMakeLists.txt | 1 - + lld/tools/lld/lld.cpp | 12 +- + 87 files changed, 4 insertions(+), 7244 deletions(-) + delete mode 100644 lld/MachO/Arch/X86_64.cpp + delete mode 100644 lld/MachO/CMakeLists.txt + delete mode 100644 lld/MachO/Config.h + delete mode 100644 lld/MachO/Driver.cpp + delete mode 100644 lld/MachO/Driver.h + delete mode 100644 lld/MachO/ExportTrie.cpp + delete mode 100644 lld/MachO/ExportTrie.h + delete mode 100644 lld/MachO/InputFiles.cpp + delete mode 100644 lld/MachO/InputFiles.h + delete mode 100644 lld/MachO/InputSection.cpp + delete mode 100644 lld/MachO/InputSection.h + delete mode 100644 lld/MachO/MachOStructs.h + delete mode 100644 lld/MachO/MergedOutputSection.cpp + delete mode 100644 lld/MachO/MergedOutputSection.h + delete mode 100644 lld/MachO/Options.td + delete mode 100644 lld/MachO/OutputSection.cpp + delete mode 100644 lld/MachO/OutputSection.h + delete mode 100644 lld/MachO/OutputSegment.cpp + delete mode 100644 lld/MachO/OutputSegment.h + delete mode 100644 lld/MachO/SymbolTable.cpp + delete mode 100644 lld/MachO/SymbolTable.h + delete mode 100644 lld/MachO/Symbols.cpp + delete mode 100644 lld/MachO/Symbols.h + delete mode 100644 lld/MachO/SyntheticSections.cpp + delete mode 100644 lld/MachO/SyntheticSections.h + delete mode 100644 lld/MachO/Target.cpp + delete mode 100644 lld/MachO/Target.h + delete mode 100644 lld/MachO/Writer.cpp + delete mode 100644 lld/MachO/Writer.h + delete mode 100644 lld/test/MachO/Inputs/MacOSX.sdk/usr/lib/libSystem.tbd + delete mode 100644 lld/test/MachO/Inputs/iPhoneSimulator.sdk/usr/lib/libSystem.tbd + delete mode 100644 lld/test/MachO/Inputs/libfunction.s + delete mode 100644 lld/test/MachO/Inputs/libgoodbye.s + delete mode 100644 lld/test/MachO/Inputs/libhello.s + delete mode 100644 lld/test/MachO/arch.s + delete mode 100644 lld/test/MachO/archive.s + delete mode 100644 lld/test/MachO/bss.s + delete mode 100644 lld/test/MachO/dylib.s + delete mode 100644 lld/test/MachO/dylink-lazy.s + delete mode 100644 lld/test/MachO/dylink.s + delete mode 100644 lld/test/MachO/entry-symbol.s + delete mode 100644 lld/test/MachO/export-trie.s + delete mode 100644 lld/test/MachO/fat-arch.s + delete mode 100644 lld/test/MachO/invalid/alignment-too-large.yaml + delete mode 100644 lld/test/MachO/invalid/archive-no-index.s + delete mode 100644 lld/test/MachO/invalid/bad-archive.s + delete mode 100644 lld/test/MachO/invalid/duplicate-symbol.s + delete mode 100644 lld/test/MachO/invalid/invalid-executable.s + delete mode 100644 lld/test/MachO/invalid/invalid-fat-narch.s + delete mode 100644 lld/test/MachO/invalid/invalid-fat-offset.s + delete mode 100644 lld/test/MachO/invalid/invalid-relocation-length.yaml + delete mode 100644 lld/test/MachO/invalid/invalid-relocation-pcrel.yaml + delete mode 100644 lld/test/MachO/invalid/missing-dylib.s + delete mode 100644 lld/test/MachO/invalid/no-id-dylink.yaml + delete mode 100644 lld/test/MachO/invalid/no-such-file.s + delete mode 100644 lld/test/MachO/invalid/order-file-bad-arch.test + delete mode 100644 lld/test/MachO/invalid/order-file-bad-objfile.test + delete mode 100644 lld/test/MachO/invalid/reserved-section-name.s + delete mode 100644 lld/test/MachO/invalid/stub-link.s + delete mode 100644 lld/test/MachO/invalid/undefined-symbol.s + delete mode 100644 lld/test/MachO/link-search-order.s + delete mode 100644 lld/test/MachO/load-commands.s + delete mode 100644 lld/test/MachO/local-got.s + delete mode 100644 lld/test/MachO/no-exports-dylib.s + delete mode 100644 lld/test/MachO/order-file.s + delete mode 100644 lld/test/MachO/platform-version.test + delete mode 100644 lld/test/MachO/relocations.s + delete mode 100644 lld/test/MachO/resolution.s + delete mode 100644 lld/test/MachO/search-paths-darwin.test + delete mode 100644 lld/test/MachO/search-paths.test + delete mode 100644 lld/test/MachO/section-headers.s + delete mode 100644 lld/test/MachO/section-merge.s + delete mode 100644 lld/test/MachO/segments.s + delete mode 100644 lld/test/MachO/silent-ignore.test + delete mode 100644 lld/test/MachO/static-link.s + delete mode 100644 lld/test/MachO/stub-link.s + delete mode 100644 lld/test/MachO/sub-library.s + delete mode 100644 lld/test/MachO/subsections-section-relocs.s + delete mode 100644 lld/test/MachO/subsections-symbol-relocs.s + delete mode 100644 lld/test/MachO/symbol-order.s + delete mode 100644 lld/test/MachO/symtab.s + delete mode 100644 lld/test/MachO/x86-64-reloc-signed.s + delete mode 100644 lld/test/MachO/x86-64-reloc-unsigned.s + +diff --git a/lld/CMakeLists.txt b/lld/CMakeLists.txt +index 5090c935e75..a0f2132c0f5 100644 +--- a/lld/CMakeLists.txt ++++ b/lld/CMakeLists.txt +@@ -223,7 +223,6 @@ endif() + add_subdirectory(docs) + add_subdirectory(COFF) + add_subdirectory(ELF) +-add_subdirectory(MachO) + add_subdirectory(MinGW) + add_subdirectory(wasm) + +diff --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp +deleted file mode 100644 +index 36f686ca2f1..00000000000 +--- a/lld/MachO/Arch/X86_64.cpp ++++ /dev/null +@@ -1,286 +0,0 @@ +-//===- X86_64.cpp ---------------------------------------------------------===// +-// +-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +-// See https://llvm.org/LICENSE.txt for license information. +-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +-// +-//===----------------------------------------------------------------------===// +- +-#include "InputFiles.h" +-#include "Symbols.h" +-#include "SyntheticSections.h" +-#include "Target.h" +- +-#include "lld/Common/ErrorHandler.h" +-#include "llvm/BinaryFormat/MachO.h" +-#include "llvm/Support/Endian.h" +- +-using namespace llvm::MachO; +-using namespace llvm::support::endian; +-using namespace lld; +-using namespace lld::macho; +- +-namespace { +- +-struct X86_64 : TargetInfo { +- X86_64(); +- +- uint64_t getImplicitAddend(MemoryBufferRef, const section_64 &, +- const relocation_info &) const override; +- void relocateOne(uint8_t *loc, const Reloc &, uint64_t val) const override; +- +- void writeStub(uint8_t *buf, const DylibSymbol &) const override; +- void writeStubHelperHeader(uint8_t *buf) const override; +- void writeStubHelperEntry(uint8_t *buf, const DylibSymbol &, +- uint64_t entryAddr) const override; +- +- void prepareSymbolRelocation(lld::macho::Symbol &, const InputSection *, +- const Reloc &) override; +- uint64_t getSymbolVA(const lld::macho::Symbol &, uint8_t type) const override; +-}; +- +-} // namespace +- +-static std::string getErrorLocation(MemoryBufferRef mb, const section_64 &sec, +- const relocation_info &rel) { +- return ("invalid relocation at offset " + std::to_string(rel.r_address) + +- " of " + sec.segname + "," + sec.sectname + " in " + +- mb.getBufferIdentifier()) +- .str(); +-} +- +-static void validateLength(MemoryBufferRef mb, const section_64 &sec, +- const relocation_info &rel, +- const std::vector &validLengths) { +- if (std::find(validLengths.begin(), validLengths.end(), rel.r_length) != +- validLengths.end()) +- return; +- +- std::string msg = getErrorLocation(mb, sec, rel) + ": relocations of type " + +- std::to_string(rel.r_type) + " must have r_length of "; +- bool first = true; +- for (uint8_t length : validLengths) { +- if (!first) +- msg += " or "; +- first = false; +- msg += std::to_string(length); +- } +- fatal(msg); +-} +- +-uint64_t X86_64::getImplicitAddend(MemoryBufferRef mb, const section_64 &sec, +- const relocation_info &rel) const { +- auto *buf = reinterpret_cast(mb.getBufferStart()); +- const uint8_t *loc = buf + sec.offset + rel.r_address; +- switch (rel.r_type) { +- case X86_64_RELOC_BRANCH: +- // XXX: ld64 also supports r_length = 0 here but I'm not sure when such a +- // relocation will actually be generated. +- validateLength(mb, sec, rel, {2}); +- break; +- case X86_64_RELOC_SIGNED: +- case X86_64_RELOC_SIGNED_1: +- case X86_64_RELOC_SIGNED_2: +- case X86_64_RELOC_SIGNED_4: +- case X86_64_RELOC_GOT_LOAD: +- case X86_64_RELOC_GOT: +- if (!rel.r_pcrel) +- fatal(getErrorLocation(mb, sec, rel) + ": relocations of type " + +- std::to_string(rel.r_type) + " must be pcrel"); +- validateLength(mb, sec, rel, {2}); +- break; +- case X86_64_RELOC_UNSIGNED: +- if (rel.r_pcrel) +- fatal(getErrorLocation(mb, sec, rel) + ": relocations of type " + +- std::to_string(rel.r_type) + " must not be pcrel"); +- validateLength(mb, sec, rel, {2, 3}); +- break; +- default: +- error("TODO: Unhandled relocation type " + std::to_string(rel.r_type)); +- return 0; +- } +- +- switch (rel.r_length) { +- case 0: +- return *loc; +- case 1: +- return read16le(loc); +- case 2: +- return read32le(loc); +- case 3: +- return read64le(loc); +- default: +- llvm_unreachable("invalid r_length"); +- } +-} +- +-void X86_64::relocateOne(uint8_t *loc, const Reloc &r, uint64_t val) const { +- switch (r.type) { +- case X86_64_RELOC_BRANCH: +- case X86_64_RELOC_SIGNED: +- case X86_64_RELOC_SIGNED_1: +- case X86_64_RELOC_SIGNED_2: +- case X86_64_RELOC_SIGNED_4: +- case X86_64_RELOC_GOT_LOAD: +- case X86_64_RELOC_GOT: +- // These types are only used for pc-relative relocations, so offset by 4 +- // since the RIP has advanced by 4 at this point. This is only valid when +- // r_length = 2, which is enforced by validateLength(). +- val -= 4; +- break; +- case X86_64_RELOC_UNSIGNED: +- break; +- default: +- llvm_unreachable( +- "getImplicitAddend should have flagged all unhandled relocation types"); +- } +- +- switch (r.length) { +- case 0: +- *loc = val; +- break; +- case 1: +- write16le(loc, val); +- break; +- case 2: +- write32le(loc, val); +- break; +- case 3: +- write64le(loc, val); +- break; +- default: +- llvm_unreachable("invalid r_length"); +- } +-} +- +-// The following methods emit a number of assembly sequences with RIP-relative +-// addressing. Note that RIP-relative addressing on X86-64 has the RIP pointing +-// to the next instruction, not the current instruction, so we always have to +-// account for the current instruction's size when calculating offsets. +-// writeRipRelative helps with that. +-// +-// bufAddr: The virtual address corresponding to buf[0]. +-// bufOff: The offset within buf of the next instruction. +-// destAddr: The destination address that the current instruction references. +-static void writeRipRelative(uint8_t *buf, uint64_t bufAddr, uint64_t bufOff, +- uint64_t destAddr) { +- uint64_t rip = bufAddr + bufOff; +- // For the instructions we care about, the RIP-relative address is always +- // stored in the last 4 bytes of the instruction. +- write32le(buf + bufOff - 4, destAddr - rip); +-} +- +-static constexpr uint8_t stub[] = { +- 0xff, 0x25, 0, 0, 0, 0, // jmpq *__la_symbol_ptr(%rip) +-}; +- +-void X86_64::writeStub(uint8_t *buf, const DylibSymbol &sym) const { +- memcpy(buf, stub, 2); // just copy the two nonzero bytes +- uint64_t stubAddr = in.stubs->addr + sym.stubsIndex * sizeof(stub); +- writeRipRelative(buf, stubAddr, sizeof(stub), +- in.lazyPointers->addr + sym.stubsIndex * WordSize); +-} +- +-static constexpr uint8_t stubHelperHeader[] = { +- 0x4c, 0x8d, 0x1d, 0, 0, 0, 0, // 0x0: leaq ImageLoaderCache(%rip), %r11 +- 0x41, 0x53, // 0x7: pushq %r11 +- 0xff, 0x25, 0, 0, 0, 0, // 0x9: jmpq *dyld_stub_binder@GOT(%rip) +- 0x90, // 0xf: nop +-}; +- +-static constexpr uint8_t stubHelperEntry[] = { +- 0x68, 0, 0, 0, 0, // 0x0: pushq +- 0xe9, 0, 0, 0, 0, // 0x5: jmp <__stub_helper> +-}; +- +-void X86_64::writeStubHelperHeader(uint8_t *buf) const { +- memcpy(buf, stubHelperHeader, sizeof(stubHelperHeader)); +- writeRipRelative(buf, in.stubHelper->addr, 7, in.imageLoaderCache->getVA()); +- writeRipRelative(buf, in.stubHelper->addr, 0xf, +- in.got->addr + +- in.stubHelper->stubBinder->gotIndex * WordSize); +-} +- +-void X86_64::writeStubHelperEntry(uint8_t *buf, const DylibSymbol &sym, +- uint64_t entryAddr) const { +- memcpy(buf, stubHelperEntry, sizeof(stubHelperEntry)); +- write32le(buf + 1, sym.lazyBindOffset); +- writeRipRelative(buf, entryAddr, sizeof(stubHelperEntry), +- in.stubHelper->addr); +-} +- +-void X86_64::prepareSymbolRelocation(lld::macho::Symbol &sym, +- const InputSection *isec, const Reloc &r) { +- switch (r.type) { +- case X86_64_RELOC_GOT_LOAD: +- // TODO: implement mov -> lea relaxation for non-dynamic symbols +- case X86_64_RELOC_GOT: +- in.got->addEntry(sym); +- break; +- case X86_64_RELOC_BRANCH: { +- if (auto *dysym = dyn_cast(&sym)) +- in.stubs->addEntry(*dysym); +- break; +- } +- case X86_64_RELOC_UNSIGNED: { +- if (auto *dysym = dyn_cast(&sym)) { +- if (r.length != 3) { +- error("X86_64_RELOC_UNSIGNED referencing the dynamic symbol " + +- dysym->getName() + " must have r_length = 3"); +- return; +- } +- in.binding->addEntry(dysym, isec, r.offset, r.addend); +- } +- break; +- } +- case X86_64_RELOC_SIGNED: +- case X86_64_RELOC_SIGNED_1: +- case X86_64_RELOC_SIGNED_2: +- case X86_64_RELOC_SIGNED_4: +- break; +- case X86_64_RELOC_SUBTRACTOR: +- case X86_64_RELOC_TLV: +- fatal("TODO: handle relocation type " + std::to_string(r.type)); +- break; +- default: +- llvm_unreachable("unexpected relocation type"); +- } +-} +- +-uint64_t X86_64::getSymbolVA(const lld::macho::Symbol &sym, +- uint8_t type) const { +- switch (type) { +- case X86_64_RELOC_GOT_LOAD: +- case X86_64_RELOC_GOT: +- return in.got->addr + sym.gotIndex * WordSize; +- case X86_64_RELOC_BRANCH: +- if (auto *dysym = dyn_cast(&sym)) +- return in.stubs->addr + dysym->stubsIndex * sizeof(stub); +- return sym.getVA(); +- case X86_64_RELOC_UNSIGNED: +- case X86_64_RELOC_SIGNED: +- case X86_64_RELOC_SIGNED_1: +- case X86_64_RELOC_SIGNED_2: +- case X86_64_RELOC_SIGNED_4: +- return sym.getVA(); +- case X86_64_RELOC_SUBTRACTOR: +- case X86_64_RELOC_TLV: +- fatal("TODO: handle relocation type " + std::to_string(type)); +- default: +- llvm_unreachable("Unexpected relocation type"); +- } +-} +- +-X86_64::X86_64() { +- cpuType = CPU_TYPE_X86_64; +- cpuSubtype = CPU_SUBTYPE_X86_64_ALL; +- +- stubSize = sizeof(stub); +- stubHelperHeaderSize = sizeof(stubHelperHeader); +- stubHelperEntrySize = sizeof(stubHelperEntry); +-} +- +-TargetInfo *macho::createX86_64TargetInfo() { +- static X86_64 t; +- return &t; +-} +diff --git a/lld/MachO/CMakeLists.txt b/lld/MachO/CMakeLists.txt +deleted file mode 100644 +index 6fe356f5158..00000000000 +--- a/lld/MachO/CMakeLists.txt ++++ /dev/null +@@ -1,36 +0,0 @@ +-set(LLVM_TARGET_DEFINITIONS Options.td) +-tablegen(LLVM Options.inc -gen-opt-parser-defs) +-add_public_tablegen_target(MachOOptionsTableGen) +- +-add_lld_library(lldMachO2 +- Arch/X86_64.cpp +- Driver.cpp +- ExportTrie.cpp +- InputFiles.cpp +- InputSection.cpp +- MergedOutputSection.cpp +- OutputSection.cpp +- OutputSegment.cpp +- SymbolTable.cpp +- Symbols.cpp +- SyntheticSections.cpp +- Target.cpp +- Writer.cpp +- +- LINK_COMPONENTS +- ${LLVM_TARGETS_TO_BUILD} +- BinaryFormat +- Core +- Object +- Option +- Support +- TextAPI +- +- LINK_LIBS +- lldCommon +- ${LLVM_PTHREAD_LIB} +- +- DEPENDS +- MachOOptionsTableGen +- ${tablegen_deps} +- ) +diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h +deleted file mode 100644 +index 79812a43356..00000000000 +--- a/lld/MachO/Config.h ++++ /dev/null +@@ -1,57 +0,0 @@ +-//===- Config.h -------------------------------------------------*- C++ -*-===// +-// +-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +-// See https://llvm.org/LICENSE.txt for license information. +-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLD_MACHO_CONFIG_H +-#define LLD_MACHO_CONFIG_H +- +-#include "llvm/ADT/DenseMap.h" +-#include "llvm/ADT/StringRef.h" +-#include "llvm/BinaryFormat/MachO.h" +-#include "llvm/TextAPI/MachO/Architecture.h" +- +-#include +- +-namespace lld { +-namespace macho { +- +-class Symbol; +-struct SymbolPriorityEntry; +- +-struct Configuration { +- Symbol *entry; +- bool hasReexports = false; +- llvm::StringRef installName; +- llvm::StringRef outputFile; +- llvm::MachO::Architecture arch; +- llvm::MachO::HeaderFileType outputType; +- std::vector librarySearchPaths; +- // TODO: use the framework search paths +- std::vector frameworkSearchPaths; +- llvm::DenseMap priorities; +-}; +- +-// The symbol with the highest priority should be ordered first in the output +-// section (modulo input section contiguity constraints). Using priority +-// (highest first) instead of order (lowest first) has the convenient property +-// that the default-constructed zero priority -- for symbols/sections without a +-// user-defined order -- naturally ends up putting them at the end of the +-// output. +-struct SymbolPriorityEntry { +- // The priority given to a matching symbol, regardless of which object file +- // it originated from. +- size_t anyObjectFile = 0; +- // The priority given to a matching symbol from a particular object file. +- llvm::DenseMap objectFiles; +-}; +- +-extern Configuration *config; +- +-} // namespace macho +-} // namespace lld +- +-#endif +diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp +deleted file mode 100644 +index 2a3b0042162..00000000000 +--- a/lld/MachO/Driver.cpp ++++ /dev/null +@@ -1,451 +0,0 @@ +-//===- Driver.cpp ---------------------------------------------------------===// +-// +-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +-// See https://llvm.org/LICENSE.txt for license information. +-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +-// +-//===----------------------------------------------------------------------===// +- +-#include "Driver.h" +-#include "Config.h" +-#include "InputFiles.h" +-#include "OutputSection.h" +-#include "OutputSegment.h" +-#include "SymbolTable.h" +-#include "Symbols.h" +-#include "Target.h" +-#include "Writer.h" +- +-#include "lld/Common/Args.h" +-#include "lld/Common/Driver.h" +-#include "lld/Common/ErrorHandler.h" +-#include "lld/Common/LLVM.h" +-#include "lld/Common/Memory.h" +-#include "lld/Common/Version.h" +-#include "llvm/ADT/DenseSet.h" +-#include "llvm/ADT/StringExtras.h" +-#include "llvm/ADT/StringRef.h" +-#include "llvm/BinaryFormat/MachO.h" +-#include "llvm/BinaryFormat/Magic.h" +-#include "llvm/Object/Archive.h" +-#include "llvm/Option/ArgList.h" +-#include "llvm/Option/Option.h" +-#include "llvm/Support/Host.h" +-#include "llvm/Support/MemoryBuffer.h" +-#include "llvm/Support/Path.h" +- +-using namespace llvm; +-using namespace llvm::MachO; +-using namespace llvm::sys; +-using namespace llvm::opt; +-using namespace lld; +-using namespace lld::macho; +- +-Configuration *lld::macho::config; +- +-// Create prefix string literals used in Options.td +-#define PREFIX(NAME, VALUE) const char *NAME[] = VALUE; +-#include "Options.inc" +-#undef PREFIX +- +-// Create table mapping all options defined in Options.td +-static const opt::OptTable::Info optInfo[] = { +-#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ +- {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ +- X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, +-#include "Options.inc" +-#undef OPTION +-}; +- +-MachOOptTable::MachOOptTable() : OptTable(optInfo) {} +- +-opt::InputArgList MachOOptTable::parse(ArrayRef argv) { +- // Make InputArgList from string vectors. +- unsigned missingIndex; +- unsigned missingCount; +- SmallVector vec(argv.data(), argv.data() + argv.size()); +- +- opt::InputArgList args = ParseArgs(vec, missingIndex, missingCount); +- +- if (missingCount) +- error(Twine(args.getArgString(missingIndex)) + ": missing argument"); +- +- for (opt::Arg *arg : args.filtered(OPT_UNKNOWN)) +- error("unknown argument: " + arg->getSpelling()); +- return args; +-} +- +-void MachOOptTable::printHelp(const char *argv0, bool showHidden) const { +- PrintHelp(lld::outs(), (std::string(argv0) + " [options] file...").c_str(), +- "LLVM Linker", showHidden); +- lld::outs() << "\n"; +-} +- +-static Optional findLibrary(StringRef name) { +- std::string stub = (llvm::Twine("lib") + name + ".tbd").str(); +- std::string shared = (llvm::Twine("lib") + name + ".dylib").str(); +- std::string archive = (llvm::Twine("lib") + name + ".a").str(); +- llvm::SmallString<260> location; +- +- for (StringRef dir : config->librarySearchPaths) { +- for (StringRef library : {stub, shared, archive}) { +- location = dir; +- llvm::sys::path::append(location, library); +- if (fs::exists(location)) +- return location.str().str(); +- } +- } +- return {}; +-} +- +-static TargetInfo *createTargetInfo(opt::InputArgList &args) { +- StringRef arch = args.getLastArgValue(OPT_arch, "x86_64"); +- config->arch = llvm::MachO::getArchitectureFromName( +- args.getLastArgValue(OPT_arch, arch)); +- switch (config->arch) { +- case llvm::MachO::AK_x86_64: +- case llvm::MachO::AK_x86_64h: +- return createX86_64TargetInfo(); +- default: +- fatal("missing or unsupported -arch " + arch); +- } +-} +- +-static bool isDirectory(StringRef option, StringRef path) { +- if (!fs::exists(path)) { +- warn("directory not found for option -" + option + path); +- return false; +- } else if (!fs::is_directory(path)) { +- warn("option -" + option + path + " references a non-directory path"); +- return false; +- } +- return true; +-} +- +-static void getSearchPaths(std::vector &paths, unsigned optionCode, +- opt::InputArgList &args, +- const SmallVector &systemPaths) { +- StringRef optionLetter{(optionCode == OPT_F ? "F" : "L")}; +- for (auto const &path : args::getStrings(args, optionCode)) { +- if (isDirectory(optionLetter, path)) +- paths.push_back(path); +- } +- if (!args.hasArg(OPT_Z) && Triple(sys::getProcessTriple()).isOSDarwin()) { +- for (auto const &path : systemPaths) { +- if (isDirectory(optionLetter, path)) +- paths.push_back(path); +- } +- } +-} +- +-static void getLibrarySearchPaths(std::vector &paths, +- opt::InputArgList &args) { +- getSearchPaths(paths, OPT_L, args, {"/usr/lib", "/usr/local/lib"}); +-} +- +-static void getFrameworkSearchPaths(std::vector &paths, +- opt::InputArgList &args) { +- getSearchPaths(paths, OPT_F, args, +- {"/Library/Frameworks", "/System/Library/Frameworks"}); +-} +- +-static void addFile(StringRef path) { +- Optional buffer = readFile(path); +- if (!buffer) +- return; +- MemoryBufferRef mbref = *buffer; +- +- switch (identify_magic(mbref.getBuffer())) { +- case file_magic::archive: { +- std::unique_ptr file = CHECK( +- object::Archive::create(mbref), path + ": failed to parse archive"); +- +- if (!file->isEmpty() && !file->hasSymbolTable()) +- error(path + ": archive has no index; run ranlib to add one"); +- +- inputFiles.push_back(make(std::move(file))); +- break; +- } +- case file_magic::macho_object: +- inputFiles.push_back(make(mbref)); +- break; +- case file_magic::macho_dynamically_linked_shared_lib: +- inputFiles.push_back(make(mbref)); +- break; +- case file_magic::tapi_file: { +- llvm::Expected> result = +- TextAPIReader::get(mbref); +- if (!result) +- return; +- +- inputFiles.push_back(make(std::move(*result))); +- break; +- } +- default: +- error(path + ": unhandled file type"); +- } +-} +- +-static std::array archNames{"arm", "arm64", "i386", +- "x86_64", "ppc", "ppc64"}; +-static bool isArchString(StringRef s) { +- static DenseSet archNamesSet(archNames.begin(), archNames.end()); +- return archNamesSet.find(s) != archNamesSet.end(); +-} +- +-// An order file has one entry per line, in the following format: +-// +-// :: +-// +-// and are optional. If not specified, then that entry +-// matches any symbol of that name. +-// +-// If a symbol is matched by multiple entries, then it takes the lowest-ordered +-// entry (the one nearest to the front of the list.) +-// +-// The file can also have line comments that start with '#'. +-void parseOrderFile(StringRef path) { +- Optional buffer = readFile(path); +- if (!buffer) { +- error("Could not read order file at " + path); +- return; +- } +- +- MemoryBufferRef mbref = *buffer; +- size_t priority = std::numeric_limits::max(); +- for (StringRef rest : args::getLines(mbref)) { +- StringRef arch, objectFile, symbol; +- +- std::array fields; +- uint8_t fieldCount = 0; +- while (rest != "" && fieldCount < 3) { +- std::pair p = getToken(rest, ": \t\n\v\f\r"); +- StringRef tok = p.first; +- rest = p.second; +- +- // Check if we have a comment +- if (tok == "" || tok[0] == '#') +- break; +- +- fields[fieldCount++] = tok; +- } +- +- switch (fieldCount) { +- case 3: +- arch = fields[0]; +- objectFile = fields[1]; +- symbol = fields[2]; +- break; +- case 2: +- (isArchString(fields[0]) ? arch : objectFile) = fields[0]; +- symbol = fields[1]; +- break; +- case 1: +- symbol = fields[0]; +- break; +- case 0: +- break; +- default: +- llvm_unreachable("too many fields in order file"); +- } +- +- if (!arch.empty()) { +- if (!isArchString(arch)) { +- error("invalid arch \"" + arch + "\" in order file: expected one of " + +- llvm::join(archNames, ", ")); +- continue; +- } +- +- // TODO: Update when we extend support for other archs +- if (arch != "x86_64") +- continue; +- } +- +- if (!objectFile.empty() && !objectFile.endswith(".o")) { +- error("invalid object file name \"" + objectFile + +- "\" in order file: should end with .o"); +- continue; +- } +- +- if (!symbol.empty()) { +- SymbolPriorityEntry &entry = config->priorities[symbol]; +- if (!objectFile.empty()) +- entry.objectFiles.insert(std::make_pair(objectFile, priority)); +- else +- entry.anyObjectFile = std::max(entry.anyObjectFile, priority); +- } +- +- --priority; +- } +-} +- +-// We expect sub-library names of the form "libfoo", which will match a dylib +-// with a path of .*/libfoo.dylib. +-static bool markSubLibrary(StringRef searchName) { +- for (InputFile *file : inputFiles) { +- if (auto *dylibFile = dyn_cast(file)) { +- StringRef filename = path::filename(dylibFile->getName()); +- if (filename.consume_front(searchName) && filename == ".dylib") { +- dylibFile->reexport = true; +- return true; +- } +- } +- } +- return false; +-} +- +-static void handlePlatformVersion(const opt::Arg *arg) { +- // TODO: implementation coming very soon ... +-} +- +-static void warnIfDeprecatedOption(const opt::Option &opt) { +- if (!opt.getGroup().isValid()) +- return; +- if (opt.getGroup().getID() == OPT_grp_deprecated) { +- warn("Option `" + opt.getPrefixedName() + "' is deprecated in ld64:"); +- warn(opt.getHelpText()); +- } +-} +- +-static void warnIfUnimplementedOption(const opt::Option &opt) { +- if (!opt.getGroup().isValid()) +- return; +- switch (opt.getGroup().getID()) { +- case OPT_grp_deprecated: +- // warn about deprecated options elsewhere +- break; +- case OPT_grp_undocumented: +- warn("Option `" + opt.getPrefixedName() + +- "' is undocumented. Should lld implement it?"); +- break; +- case OPT_grp_obsolete: +- warn("Option `" + opt.getPrefixedName() + +- "' is obsolete. Please modernize your usage."); +- break; +- case OPT_grp_ignored: +- warn("Option `" + opt.getPrefixedName() + "' is ignored."); +- break; +- default: +- warn("Option `" + opt.getPrefixedName() + +- "' is not yet implemented. Stay tuned..."); +- break; +- } +-} +- +-bool macho::link(llvm::ArrayRef argsArr, bool canExitEarly, +- raw_ostream &stdoutOS, raw_ostream &stderrOS) { +- lld::stdoutOS = &stdoutOS; +- lld::stderrOS = &stderrOS; +- +- stderrOS.enable_colors(stderrOS.has_colors()); +- // TODO: Set up error handler properly, e.g. the errorLimitExceededMsg +- +- MachOOptTable parser; +- opt::InputArgList args = parser.parse(argsArr.slice(1)); +- +- if (args.hasArg(OPT_help_hidden)) { +- parser.printHelp(argsArr[0], /*showHidden=*/true); +- return true; +- } else if (args.hasArg(OPT_help)) { +- parser.printHelp(argsArr[0], /*showHidden=*/false); +- return true; +- } +- +- config = make(); +- symtab = make(); +- target = createTargetInfo(args); +- +- config->entry = symtab->addUndefined(args.getLastArgValue(OPT_e, "_main")); +- config->outputFile = args.getLastArgValue(OPT_o, "a.out"); +- config->installName = +- args.getLastArgValue(OPT_install_name, config->outputFile); +- getLibrarySearchPaths(config->librarySearchPaths, args); +- getFrameworkSearchPaths(config->frameworkSearchPaths, args); +- config->outputType = args.hasArg(OPT_dylib) ? MH_DYLIB : MH_EXECUTE; +- +- if (args.hasArg(OPT_v)) { +- message(getLLDVersion()); +- message(StringRef("Library search paths:") + +- (config->librarySearchPaths.size() +- ? "\n\t" + llvm::join(config->librarySearchPaths, "\n\t") +- : "")); +- message(StringRef("Framework search paths:") + +- (config->frameworkSearchPaths.size() +- ? "\n\t" + llvm::join(config->frameworkSearchPaths, "\n\t") +- : "")); +- freeArena(); +- return !errorCount(); +- } +- +- for (const auto &arg : args) { +- const auto &opt = arg->getOption(); +- warnIfDeprecatedOption(opt); +- switch (arg->getOption().getID()) { +- case OPT_INPUT: +- addFile(arg->getValue()); +- break; +- case OPT_l: { +- StringRef name = arg->getValue(); +- if (Optional path = findLibrary(name)) { +- addFile(*path); +- break; +- } +- error("library not found for -l" + name); +- break; +- } +- case OPT_platform_version: +- handlePlatformVersion(arg); +- break; +- case OPT_o: +- case OPT_dylib: +- case OPT_e: +- case OPT_L: +- case OPT_Z: +- case OPT_arch: +- // handled elsewhere +- break; +- default: +- warnIfUnimplementedOption(opt); +- break; +- } +- } +- +- // Now that all dylibs have been loaded, search for those that should be +- // re-exported. +- for (opt::Arg *arg : args.filtered(OPT_sub_library)) { +- config->hasReexports = true; +- StringRef searchName = arg->getValue(); +- if (!markSubLibrary(searchName)) +- error("-sub_library " + searchName + " does not match a supplied dylib"); +- } +- +- StringRef orderFile = args.getLastArgValue(OPT_order_file); +- if (!orderFile.empty()) +- parseOrderFile(orderFile); +- +- if (config->outputType == MH_EXECUTE && !isa(config->entry)) { +- error("undefined symbol: " + config->entry->getName()); +- return false; +- } +- +- createSyntheticSections(); +- +- // Initialize InputSections. +- for (InputFile *file : inputFiles) { +- for (SubsectionMap &map : file->subsections) { +- for (auto &p : map) { +- InputSection *isec = p.second; +- inputSections.push_back(isec); +- } +- } +- } +- +- // Write to an output file. +- writeResult(); +- +- if (canExitEarly) +- exitLld(errorCount() ? 1 : 0); +- +- freeArena(); +- return !errorCount(); +-} +diff --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h +deleted file mode 100644 +index 2233740d1db..00000000000 +--- a/lld/MachO/Driver.h ++++ /dev/null +@@ -1,36 +0,0 @@ +-//===- Driver.h -------------------------------------------------*- C++ -*-===// +-// +-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +-// See https://llvm.org/LICENSE.txt for license information. +-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLD_MACHO_DRIVER_H +-#define LLD_MACHO_DRIVER_H +- +-#include "lld/Common/LLVM.h" +-#include "llvm/Option/OptTable.h" +- +-namespace lld { +-namespace macho { +- +-class MachOOptTable : public llvm::opt::OptTable { +-public: +- MachOOptTable(); +- llvm::opt::InputArgList parse(ArrayRef argv); +- void printHelp(const char *argv0, bool showHidden) const; +-}; +- +-// Create enum with OPT_xxx values for each option in Options.td +-enum { +- OPT_INVALID = 0, +-#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, +-#include "Options.inc" +-#undef OPTION +-}; +- +-} // namespace macho +-} // namespace lld +- +-#endif +diff --git a/lld/MachO/ExportTrie.cpp b/lld/MachO/ExportTrie.cpp +deleted file mode 100644 +index 7cc81bcfd5f..00000000000 +--- a/lld/MachO/ExportTrie.cpp ++++ /dev/null +@@ -1,283 +0,0 @@ +-//===- ExportTrie.cpp -----------------------------------------------------===// +-// +-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +-// See https://llvm.org/LICENSE.txt for license information. +-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +-// +-//===----------------------------------------------------------------------===// +-// +-// This is a partial implementation of the Mach-O export trie format. It's +-// essentially a symbol table encoded as a compressed prefix trie, meaning that +-// the common prefixes of each symbol name are shared for a more compact +-// representation. The prefixes are stored on the edges of the trie, and one +-// edge can represent multiple characters. For example, given two exported +-// symbols _bar and _baz, we will have a trie like this (terminal nodes are +-// marked with an asterisk): +-// +-// +-+-+ +-// | | // root node +-// +-+-+ +-// | +-// | _ba +-// | +-// +-+-+ +-// | | +-// +-+-+ +-// r / \ z +-// / \ +-// +-+-+ +-+-+ +-// | * | | * | +-// +-+-+ +-+-+ +-// +-// More documentation of the format can be found in +-// llvm/tools/obj2yaml/macho2yaml.cpp. +-// +-//===----------------------------------------------------------------------===// +- +-#include "ExportTrie.h" +-#include "Symbols.h" +- +-#include "lld/Common/ErrorHandler.h" +-#include "lld/Common/Memory.h" +-#include "llvm/ADT/Optional.h" +-#include "llvm/BinaryFormat/MachO.h" +-#include "llvm/Support/LEB128.h" +- +-using namespace llvm; +-using namespace llvm::MachO; +-using namespace lld; +-using namespace lld::macho; +- +-namespace { +- +-struct Edge { +- Edge(StringRef s, TrieNode *node) : substring(s), child(node) {} +- +- StringRef substring; +- struct TrieNode *child; +-}; +- +-struct ExportInfo { +- uint64_t address; +- // TODO: Add proper support for re-exports & stub-and-resolver flags. +-}; +- +-} // namespace +- +-struct macho::TrieNode { +- std::vector edges; +- Optional info; +- // Estimated offset from the start of the serialized trie to the current node. +- // This will converge to the true offset when updateOffset() is run to a +- // fixpoint. +- size_t offset = 0; +- +- // Returns whether the new estimated offset differs from the old one. +- bool updateOffset(size_t &nextOffset); +- void writeTo(uint8_t *buf) const; +-}; +- +-bool TrieNode::updateOffset(size_t &nextOffset) { +- // Size of the whole node (including the terminalSize and the outgoing edges.) +- // In contrast, terminalSize only records the size of the other data in the +- // node. +- size_t nodeSize; +- if (info) { +- uint64_t flags = 0; +- uint32_t terminalSize = +- getULEB128Size(flags) + getULEB128Size(info->address); +- // Overall node size so far is the uleb128 size of the length of the symbol +- // info + the symbol info itself. +- nodeSize = terminalSize + getULEB128Size(terminalSize); +- } else { +- nodeSize = 1; // Size of terminalSize (which has a value of 0) +- } +- // Compute size of all child edges. +- ++nodeSize; // Byte for number of children. +- for (Edge &edge : edges) { +- nodeSize += edge.substring.size() + 1 // String length. +- + getULEB128Size(edge.child->offset); // Offset len. +- } +- // On input, 'nextOffset' is the new preferred location for this node. +- bool result = (offset != nextOffset); +- // Store new location in node object for use by parents. +- offset = nextOffset; +- nextOffset += nodeSize; +- return result; +-} +- +-void TrieNode::writeTo(uint8_t *buf) const { +- buf += offset; +- if (info) { +- // TrieNodes with Symbol info: size, flags address +- uint64_t flags = 0; // TODO: emit proper flags +- uint32_t terminalSize = +- getULEB128Size(flags) + getULEB128Size(info->address); +- buf += encodeULEB128(terminalSize, buf); +- buf += encodeULEB128(flags, buf); +- buf += encodeULEB128(info->address, buf); +- } else { +- // TrieNode with no Symbol info. +- *buf++ = 0; // terminalSize +- } +- // Add number of children. TODO: Handle case where we have more than 256. +- assert(edges.size() < 256); +- *buf++ = edges.size(); +- // Append each child edge substring and node offset. +- for (const Edge &edge : edges) { +- memcpy(buf, edge.substring.data(), edge.substring.size()); +- buf += edge.substring.size(); +- *buf++ = '\0'; +- buf += encodeULEB128(edge.child->offset, buf); +- } +-} +- +-TrieNode *TrieBuilder::makeNode() { +- auto *node = make(); +- nodes.emplace_back(node); +- return node; +-} +- +-static int charAt(const Symbol *sym, size_t pos) { +- StringRef str = sym->getName(); +- if (pos >= str.size()) +- return -1; +- return str[pos]; +-} +- +-// Build the trie by performing a three-way radix quicksort: We start by sorting +-// the strings by their first characters, then sort the strings with the same +-// first characters by their second characters, and so on recursively. Each +-// time the prefixes diverge, we add a node to the trie. +-// +-// node: The most recently created node along this path in the trie (i.e. +-// the furthest from the root.) +-// lastPos: The prefix length of the most recently created node, i.e. the number +-// of characters along its path from the root. +-// pos: The string index we are currently sorting on. Note that each symbol +-// S contained in vec has the same prefix S[0...pos). +-void TrieBuilder::sortAndBuild(MutableArrayRef vec, +- TrieNode *node, size_t lastPos, size_t pos) { +-tailcall: +- if (vec.empty()) +- return; +- +- // Partition items so that items in [0, i) are less than the pivot, +- // [i, j) are the same as the pivot, and [j, vec.size()) are greater than +- // the pivot. +- const Symbol *pivotSymbol = vec[vec.size() / 2]; +- int pivot = charAt(pivotSymbol, pos); +- size_t i = 0; +- size_t j = vec.size(); +- for (size_t k = 0; k < j;) { +- int c = charAt(vec[k], pos); +- if (c < pivot) +- std::swap(vec[i++], vec[k++]); +- else if (c > pivot) +- std::swap(vec[--j], vec[k]); +- else +- k++; +- } +- +- bool isTerminal = pivot == -1; +- bool prefixesDiverge = i != 0 || j != vec.size(); +- if (lastPos != pos && (isTerminal || prefixesDiverge)) { +- TrieNode *newNode = makeNode(); +- node->edges.emplace_back(pivotSymbol->getName().slice(lastPos, pos), +- newNode); +- node = newNode; +- lastPos = pos; +- } +- +- sortAndBuild(vec.slice(0, i), node, lastPos, pos); +- sortAndBuild(vec.slice(j), node, lastPos, pos); +- +- if (isTerminal) { +- assert(j - i == 1); // no duplicate symbols +- node->info = {pivotSymbol->getVA()}; +- } else { +- // This is the tail-call-optimized version of the following: +- // sortAndBuild(vec.slice(i, j - i), node, lastPos, pos + 1); +- vec = vec.slice(i, j - i); +- ++pos; +- goto tailcall; +- } +-} +- +-size_t TrieBuilder::build() { +- if (exported.empty()) +- return 0; +- +- TrieNode *root = makeNode(); +- sortAndBuild(exported, root, 0, 0); +- +- // Assign each node in the vector an offset in the trie stream, iterating +- // until all uleb128 sizes have stabilized. +- size_t offset; +- bool more; +- do { +- offset = 0; +- more = false; +- for (TrieNode *node : nodes) +- more |= node->updateOffset(offset); +- } while (more); +- +- return offset; +-} +- +-void TrieBuilder::writeTo(uint8_t *buf) const { +- for (TrieNode *node : nodes) +- node->writeTo(buf); +-} +- +-namespace { +- +-// Parse a serialized trie and invoke a callback for each entry. +-class TrieParser { +-public: +- TrieParser(const uint8_t *buf, size_t size, const TrieEntryCallback &callback) +- : start(buf), end(start + size), callback(callback) {} +- +- void parse(const uint8_t *buf, const Twine &cumulativeString); +- +- void parse() { parse(start, ""); } +- +- const uint8_t *start; +- const uint8_t *end; +- const TrieEntryCallback &callback; +-}; +- +-} // namespace +- +-void TrieParser::parse(const uint8_t *buf, const Twine &cumulativeString) { +- if (buf >= end) +- fatal("Node offset points outside export section"); +- +- unsigned ulebSize; +- uint64_t terminalSize = decodeULEB128(buf, &ulebSize); +- buf += ulebSize; +- uint64_t flags = 0; +- size_t offset; +- if (terminalSize != 0) { +- flags = decodeULEB128(buf, &ulebSize); +- callback(cumulativeString, flags); +- } +- buf += terminalSize; +- uint8_t numEdges = *buf++; +- for (uint8_t i = 0; i < numEdges; ++i) { +- const char *cbuf = reinterpret_cast(buf); +- StringRef substring = StringRef(cbuf, strnlen(cbuf, end - buf)); +- buf += substring.size() + 1; +- offset = decodeULEB128(buf, &ulebSize); +- buf += ulebSize; +- parse(start + offset, cumulativeString + substring); +- } +-} +- +-void macho::parseTrie(const uint8_t *buf, size_t size, +- const TrieEntryCallback &callback) { +- if (size == 0) +- return; +- +- TrieParser(buf, size, callback).parse(); +-} +diff --git a/lld/MachO/ExportTrie.h b/lld/MachO/ExportTrie.h +deleted file mode 100644 +index 2bd8c33db9a..00000000000 +--- a/lld/MachO/ExportTrie.h ++++ /dev/null +@@ -1,47 +0,0 @@ +-//===- ExportTrie.h ---------------------------------------------*- C++ -*-===// +-// +-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +-// See https://llvm.org/LICENSE.txt for license information. +-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLD_MACHO_EXPORT_TRIE_H +-#define LLD_MACHO_EXPORT_TRIE_H +- +-#include "llvm/ADT/ArrayRef.h" +-#include "llvm/ADT/STLExtras.h" +- +-#include +- +-namespace lld { +-namespace macho { +- +-struct TrieNode; +-class Symbol; +- +-class TrieBuilder { +-public: +- void addSymbol(const Symbol &sym) { exported.push_back(&sym); } +- // Returns the size in bytes of the serialized trie. +- size_t build(); +- void writeTo(uint8_t *buf) const; +- +-private: +- TrieNode *makeNode(); +- void sortAndBuild(llvm::MutableArrayRef vec, TrieNode *node, +- size_t lastPos, size_t pos); +- +- std::vector exported; +- std::vector nodes; +-}; +- +-using TrieEntryCallback = +- llvm::function_ref; +- +-void parseTrie(const uint8_t *buf, size_t size, const TrieEntryCallback &); +- +-} // namespace macho +-} // namespace lld +- +-#endif +diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp +deleted file mode 100644 +index 46fe82f9882..00000000000 +--- a/lld/MachO/InputFiles.cpp ++++ /dev/null +@@ -1,433 +0,0 @@ +-//===- InputFiles.cpp -----------------------------------------------------===// +-// +-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +-// See https://llvm.org/LICENSE.txt for license information. +-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +-// +-//===----------------------------------------------------------------------===// +-// +-// This file contains functions to parse Mach-O object files. In this comment, +-// we describe the Mach-O file structure and how we parse it. +-// +-// Mach-O is not very different from ELF or COFF. The notion of symbols, +-// sections and relocations exists in Mach-O as it does in ELF and COFF. +-// +-// Perhaps the notion that is new to those who know ELF/COFF is "subsections". +-// In ELF/COFF, sections are an atomic unit of data copied from input files to +-// output files. When we merge or garbage-collect sections, we treat each +-// section as an atomic unit. In Mach-O, that's not the case. Sections can +-// consist of multiple subsections, and subsections are a unit of merging and +-// garbage-collecting. Therefore, Mach-O's subsections are more similar to +-// ELF/COFF's sections than Mach-O's sections are. +-// +-// A section can have multiple symbols. A symbol that does not have the +-// N_ALT_ENTRY attribute indicates a beginning of a subsection. Therefore, by +-// definition, a symbol is always present at the beginning of each subsection. A +-// symbol with N_ALT_ENTRY attribute does not start a new subsection and can +-// point to a middle of a subsection. +-// +-// The notion of subsections also affects how relocations are represented in +-// Mach-O. All references within a section need to be explicitly represented as +-// relocations if they refer to different subsections, because we obviously need +-// to fix up addresses if subsections are laid out in an output file differently +-// than they were in object files. To represent that, Mach-O relocations can +-// refer to an unnamed location via its address. Scattered relocations (those +-// with the R_SCATTERED bit set) always refer to unnamed locations. +-// Non-scattered relocations refer to an unnamed location if r_extern is not set +-// and r_symbolnum is zero. +-// +-// Without the above differences, I think you can use your knowledge about ELF +-// and COFF for Mach-O. +-// +-//===----------------------------------------------------------------------===// +- +-#include "InputFiles.h" +-#include "Config.h" +-#include "ExportTrie.h" +-#include "InputSection.h" +-#include "MachOStructs.h" +-#include "OutputSection.h" +-#include "SymbolTable.h" +-#include "Symbols.h" +-#include "Target.h" +- +-#include "lld/Common/ErrorHandler.h" +-#include "lld/Common/Memory.h" +-#include "llvm/BinaryFormat/MachO.h" +-#include "llvm/Support/Endian.h" +-#include "llvm/Support/MemoryBuffer.h" +-#include "llvm/Support/Path.h" +- +-using namespace llvm; +-using namespace llvm::MachO; +-using namespace llvm::support::endian; +-using namespace llvm::sys; +-using namespace lld; +-using namespace lld::macho; +- +-std::vector macho::inputFiles; +- +-// Open a given file path and return it as a memory-mapped file. +-Optional macho::readFile(StringRef path) { +- // Open a file. +- auto mbOrErr = MemoryBuffer::getFile(path); +- if (auto ec = mbOrErr.getError()) { +- error("cannot open " + path + ": " + ec.message()); +- return None; +- } +- +- std::unique_ptr &mb = *mbOrErr; +- MemoryBufferRef mbref = mb->getMemBufferRef(); +- make>(std::move(mb)); // take mb ownership +- +- // If this is a regular non-fat file, return it. +- const char *buf = mbref.getBufferStart(); +- auto *hdr = reinterpret_cast(buf); +- if (read32be(&hdr->magic) != MachO::FAT_MAGIC) +- return mbref; +- +- // Object files and archive files may be fat files, which contains +- // multiple real files for different CPU ISAs. Here, we search for a +- // file that matches with the current link target and returns it as +- // a MemoryBufferRef. +- auto *arch = reinterpret_cast(buf + sizeof(*hdr)); +- +- for (uint32_t i = 0, n = read32be(&hdr->nfat_arch); i < n; ++i) { +- if (reinterpret_cast(arch + i + 1) > +- buf + mbref.getBufferSize()) { +- error(path + ": fat_arch struct extends beyond end of file"); +- return None; +- } +- +- if (read32be(&arch[i].cputype) != target->cpuType || +- read32be(&arch[i].cpusubtype) != target->cpuSubtype) +- continue; +- +- uint32_t offset = read32be(&arch[i].offset); +- uint32_t size = read32be(&arch[i].size); +- if (offset + size > mbref.getBufferSize()) +- error(path + ": slice extends beyond end of file"); +- return MemoryBufferRef(StringRef(buf + offset, size), path.copy(bAlloc)); +- } +- +- error("unable to find matching architecture in " + path); +- return None; +-} +- +-static const load_command *findCommand(const mach_header_64 *hdr, +- uint32_t type) { +- const uint8_t *p = +- reinterpret_cast(hdr) + sizeof(mach_header_64); +- +- for (uint32_t i = 0, n = hdr->ncmds; i < n; ++i) { +- auto *cmd = reinterpret_cast(p); +- if (cmd->cmd == type) +- return cmd; +- p += cmd->cmdsize; +- } +- return nullptr; +-} +- +-void InputFile::parseSections(ArrayRef sections) { +- subsections.reserve(sections.size()); +- auto *buf = reinterpret_cast(mb.getBufferStart()); +- +- for (const section_64 &sec : sections) { +- InputSection *isec = make(); +- isec->file = this; +- isec->name = StringRef(sec.sectname, strnlen(sec.sectname, 16)); +- isec->segname = StringRef(sec.segname, strnlen(sec.segname, 16)); +- isec->data = {isZeroFill(sec.flags) ? nullptr : buf + sec.offset, +- static_cast(sec.size)}; +- if (sec.align >= 32) +- error("alignment " + std::to_string(sec.align) + " of section " + +- isec->name + " is too large"); +- else +- isec->align = 1 << sec.align; +- isec->flags = sec.flags; +- subsections.push_back({{0, isec}}); +- } +-} +- +-// Find the subsection corresponding to the greatest section offset that is <= +-// that of the given offset. +-// +-// offset: an offset relative to the start of the original InputSection (before +-// any subsection splitting has occurred). It will be updated to represent the +-// same location as an offset relative to the start of the containing +-// subsection. +-static InputSection *findContainingSubsection(SubsectionMap &map, +- uint32_t *offset) { +- auto it = std::prev(map.upper_bound(*offset)); +- *offset -= it->first; +- return it->second; +-} +- +-void InputFile::parseRelocations(const section_64 &sec, +- SubsectionMap &subsecMap) { +- auto *buf = reinterpret_cast(mb.getBufferStart()); +- ArrayRef relInfos( +- reinterpret_cast(buf + sec.reloff), +- sec.nreloc); +- +- for (const any_relocation_info &anyRel : relInfos) { +- if (anyRel.r_word0 & R_SCATTERED) +- fatal("TODO: Scattered relocations not supported"); +- +- auto rel = reinterpret_cast(anyRel); +- +- Reloc r; +- r.type = rel.r_type; +- r.pcrel = rel.r_pcrel; +- r.length = rel.r_length; +- uint64_t rawAddend = target->getImplicitAddend(mb, sec, rel); +- +- if (rel.r_extern) { +- r.target = symbols[rel.r_symbolnum]; +- r.addend = rawAddend; +- } else { +- if (rel.r_symbolnum == 0 || rel.r_symbolnum > subsections.size()) +- fatal("invalid section index in relocation for offset " + +- std::to_string(r.offset) + " in section " + sec.sectname + +- " of " + getName()); +- +- SubsectionMap &targetSubsecMap = subsections[rel.r_symbolnum - 1]; +- const section_64 &targetSec = sectionHeaders[rel.r_symbolnum - 1]; +- uint32_t targetOffset; +- if (rel.r_pcrel) { +- // The implicit addend for pcrel section relocations is the pcrel offset +- // in terms of the addresses in the input file. Here we adjust it so +- // that it describes the offset from the start of the target section. +- // TODO: The offset of 4 is probably not right for ARM64, nor for +- // relocations with r_length != 2. +- targetOffset = +- sec.addr + rel.r_address + 4 + rawAddend - targetSec.addr; +- } else { +- // The addend for a non-pcrel relocation is its absolute address. +- targetOffset = rawAddend - targetSec.addr; +- } +- r.target = findContainingSubsection(targetSubsecMap, &targetOffset); +- r.addend = targetOffset; +- } +- +- r.offset = rel.r_address; +- InputSection *subsec = findContainingSubsection(subsecMap, &r.offset); +- subsec->relocs.push_back(r); +- } +-} +- +-void InputFile::parseSymbols(ArrayRef nList, +- const char *strtab, bool subsectionsViaSymbols) { +- // resize(), not reserve(), because we are going to create N_ALT_ENTRY symbols +- // out-of-sequence. +- symbols.resize(nList.size()); +- std::vector altEntrySymIdxs; +- +- auto createDefined = [&](const structs::nlist_64 &sym, InputSection *isec, +- uint32_t value) -> Symbol * { +- StringRef name = strtab + sym.n_strx; +- if (sym.n_type & N_EXT) +- // Global defined symbol +- return symtab->addDefined(name, isec, value); +- else +- // Local defined symbol +- return make(name, isec, value); +- }; +- +- for (size_t i = 0, n = nList.size(); i < n; ++i) { +- const structs::nlist_64 &sym = nList[i]; +- +- // Undefined symbol +- if (!sym.n_sect) { +- StringRef name = strtab + sym.n_strx; +- symbols[i] = symtab->addUndefined(name); +- continue; +- } +- +- const section_64 &sec = sectionHeaders[sym.n_sect - 1]; +- SubsectionMap &subsecMap = subsections[sym.n_sect - 1]; +- uint64_t offset = sym.n_value - sec.addr; +- +- // If the input file does not use subsections-via-symbols, all symbols can +- // use the same subsection. Otherwise, we must split the sections along +- // symbol boundaries. +- if (!subsectionsViaSymbols) { +- symbols[i] = createDefined(sym, subsecMap[0], offset); +- continue; +- } +- +- // nList entries aren't necessarily arranged in address order. Therefore, +- // we can't create alt-entry symbols at this point because a later symbol +- // may split its section, which may affect which subsection the alt-entry +- // symbol is assigned to. So we need to handle them in a second pass below. +- if (sym.n_desc & N_ALT_ENTRY) { +- altEntrySymIdxs.push_back(i); +- continue; +- } +- +- // Find the subsection corresponding to the greatest section offset that is +- // <= that of the current symbol. The subsection that we find either needs +- // to be used directly or split in two. +- uint32_t firstSize = offset; +- InputSection *firstIsec = findContainingSubsection(subsecMap, &firstSize); +- +- if (firstSize == 0) { +- // Alias of an existing symbol, or the first symbol in the section. These +- // are handled by reusing the existing section. +- symbols[i] = createDefined(sym, firstIsec, 0); +- continue; +- } +- +- // We saw a symbol definition at a new offset. Split the section into two +- // subsections. The new symbol uses the second subsection. +- auto *secondIsec = make(*firstIsec); +- secondIsec->data = firstIsec->data.slice(firstSize); +- firstIsec->data = firstIsec->data.slice(0, firstSize); +- // TODO: ld64 appears to preserve the original alignment as well as each +- // subsection's offset from the last aligned address. We should consider +- // emulating that behavior. +- secondIsec->align = MinAlign(firstIsec->align, offset); +- +- subsecMap[offset] = secondIsec; +- // By construction, the symbol will be at offset zero in the new section. +- symbols[i] = createDefined(sym, secondIsec, 0); +- } +- +- for (size_t idx : altEntrySymIdxs) { +- const structs::nlist_64 &sym = nList[idx]; +- SubsectionMap &subsecMap = subsections[sym.n_sect - 1]; +- uint32_t off = sym.n_value - sectionHeaders[sym.n_sect - 1].addr; +- InputSection *subsec = findContainingSubsection(subsecMap, &off); +- symbols[idx] = createDefined(sym, subsec, off); +- } +-} +- +-ObjFile::ObjFile(MemoryBufferRef mb) : InputFile(ObjKind, mb) { +- auto *buf = reinterpret_cast(mb.getBufferStart()); +- auto *hdr = reinterpret_cast(mb.getBufferStart()); +- +- if (const load_command *cmd = findCommand(hdr, LC_SEGMENT_64)) { +- auto *c = reinterpret_cast(cmd); +- sectionHeaders = ArrayRef{ +- reinterpret_cast(c + 1), c->nsects}; +- parseSections(sectionHeaders); +- } +- +- // TODO: Error on missing LC_SYMTAB? +- if (const load_command *cmd = findCommand(hdr, LC_SYMTAB)) { +- auto *c = reinterpret_cast(cmd); +- ArrayRef nList( +- reinterpret_cast(buf + c->symoff), c->nsyms); +- const char *strtab = reinterpret_cast(buf) + c->stroff; +- bool subsectionsViaSymbols = hdr->flags & MH_SUBSECTIONS_VIA_SYMBOLS; +- parseSymbols(nList, strtab, subsectionsViaSymbols); +- } +- +- // The relocations may refer to the symbols, so we parse them after we have +- // parsed all the symbols. +- for (size_t i = 0, n = subsections.size(); i < n; ++i) +- parseRelocations(sectionHeaders[i], subsections[i]); +-} +- +-DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella) +- : InputFile(DylibKind, mb) { +- if (umbrella == nullptr) +- umbrella = this; +- +- auto *buf = reinterpret_cast(mb.getBufferStart()); +- auto *hdr = reinterpret_cast(mb.getBufferStart()); +- +- // Initialize dylibName. +- if (const load_command *cmd = findCommand(hdr, LC_ID_DYLIB)) { +- auto *c = reinterpret_cast(cmd); +- dylibName = reinterpret_cast(cmd) + read32le(&c->dylib.name); +- } else { +- error("dylib " + getName() + " missing LC_ID_DYLIB load command"); +- return; +- } +- +- // Initialize symbols. +- if (const load_command *cmd = findCommand(hdr, LC_DYLD_INFO_ONLY)) { +- auto *c = reinterpret_cast(cmd); +- parseTrie(buf + c->export_off, c->export_size, +- [&](const Twine &name, uint64_t flags) { +- symbols.push_back(symtab->addDylib(saver.save(name), umbrella)); +- }); +- } else { +- error("LC_DYLD_INFO_ONLY not found in " + getName()); +- return; +- } +- +- if (hdr->flags & MH_NO_REEXPORTED_DYLIBS) +- return; +- +- const uint8_t *p = +- reinterpret_cast(hdr) + sizeof(mach_header_64); +- for (uint32_t i = 0, n = hdr->ncmds; i < n; ++i) { +- auto *cmd = reinterpret_cast(p); +- p += cmd->cmdsize; +- if (cmd->cmd != LC_REEXPORT_DYLIB) +- continue; +- +- auto *c = reinterpret_cast(cmd); +- StringRef reexportPath = +- reinterpret_cast(c) + read32le(&c->dylib.name); +- // TODO: Expand @loader_path, @executable_path etc in reexportPath +- Optional buffer = readFile(reexportPath); +- if (!buffer) { +- error("unable to read re-exported dylib at " + reexportPath); +- return; +- } +- reexported.push_back(make(*buffer, umbrella)); +- } +-} +- +-DylibFile::DylibFile(std::shared_ptr interface, +- DylibFile *umbrella) +- : InputFile(DylibKind, MemoryBufferRef()) { +- if (umbrella == nullptr) +- umbrella = this; +- +- dylibName = saver.save(interface->getInstallName()); +- // TODO(compnerd) filter out symbols based on the target platform +- for (const auto symbol : interface->symbols()) +- if (symbol->getArchitectures().has(config->arch)) +- symbols.push_back( +- symtab->addDylib(saver.save(symbol->getName()), umbrella)); +- // TODO(compnerd) properly represent the hierarchy of the documents as it is +- // in theory possible to have re-exported dylibs from re-exported dylibs which +- // should be parent'ed to the child. +- for (auto document : interface->documents()) +- reexported.push_back(make(document, umbrella)); +-} +- +-ArchiveFile::ArchiveFile(std::unique_ptr &&f) +- : InputFile(ArchiveKind, f->getMemoryBufferRef()), file(std::move(f)) { +- for (const object::Archive::Symbol &sym : file->symbols()) +- symtab->addLazy(sym.getName(), this, sym); +-} +- +-void ArchiveFile::fetch(const object::Archive::Symbol &sym) { +- object::Archive::Child c = +- CHECK(sym.getMember(), toString(this) + +- ": could not get the member for symbol " + +- sym.getName()); +- +- if (!seen.insert(c.getChildOffset()).second) +- return; +- +- MemoryBufferRef mb = +- CHECK(c.getMemoryBufferRef(), +- toString(this) + +- ": could not get the buffer for the member defining symbol " + +- sym.getName()); +- auto file = make(mb); +- symbols.insert(symbols.end(), file->symbols.begin(), file->symbols.end()); +- subsections.insert(subsections.end(), file->subsections.begin(), +- file->subsections.end()); +-} +- +-// Returns "" or "baz.o". +-std::string lld::toString(const InputFile *file) { +- return file ? std::string(file->getName()) : ""; +-} +diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h +deleted file mode 100644 +index bc5ad86ccaa..00000000000 +--- a/lld/MachO/InputFiles.h ++++ /dev/null +@@ -1,121 +0,0 @@ +-//===- InputFiles.h ---------------------------------------------*- C++ -*-===// +-// +-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +-// See https://llvm.org/LICENSE.txt for license information. +-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLD_MACHO_INPUT_FILES_H +-#define LLD_MACHO_INPUT_FILES_H +- +-#include "MachOStructs.h" +- +-#include "lld/Common/LLVM.h" +-#include "llvm/ADT/DenseSet.h" +-#include "llvm/BinaryFormat/MachO.h" +-#include "llvm/Object/Archive.h" +-#include "llvm/Support/MemoryBuffer.h" +-#include "llvm/TextAPI/MachO/InterfaceFile.h" +-#include "llvm/TextAPI/MachO/TextAPIReader.h" +- +-#include +-#include +- +-namespace lld { +-namespace macho { +- +-class InputSection; +-class Symbol; +-struct Reloc; +- +-// If .subsections_via_symbols is set, each InputSection will be split along +-// symbol boundaries. The keys of a SubsectionMap represent the offsets of +-// each subsection from the start of the original pre-split InputSection. +-using SubsectionMap = std::map; +- +-class InputFile { +-public: +- enum Kind { +- ObjKind, +- DylibKind, +- ArchiveKind, +- }; +- +- virtual ~InputFile() = default; +- Kind kind() const { return fileKind; } +- StringRef getName() const { return mb.getBufferIdentifier(); } +- +- MemoryBufferRef mb; +- std::vector symbols; +- ArrayRef sectionHeaders; +- std::vector subsections; +- +-protected: +- InputFile(Kind kind, MemoryBufferRef mb) : mb(mb), fileKind(kind) {} +- +- void parseSections(ArrayRef); +- +- void parseSymbols(ArrayRef nList, const char *strtab, +- bool subsectionsViaSymbols); +- +- void parseRelocations(const llvm::MachO::section_64 &, SubsectionMap &); +- +-private: +- const Kind fileKind; +-}; +- +-// .o file +-class ObjFile : public InputFile { +-public: +- explicit ObjFile(MemoryBufferRef mb); +- static bool classof(const InputFile *f) { return f->kind() == ObjKind; } +-}; +- +-// .dylib file +-class DylibFile : public InputFile { +-public: +- explicit DylibFile(std::shared_ptr interface, +- DylibFile *umbrella = nullptr); +- +- // Mach-O dylibs can re-export other dylibs as sub-libraries, meaning that the +- // symbols in those sub-libraries will be available under the umbrella +- // library's namespace. Those sub-libraries can also have their own +- // re-exports. When loading a re-exported dylib, `umbrella` should be set to +- // 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. +- explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella = nullptr); +- +- static bool classof(const InputFile *f) { return f->kind() == DylibKind; } +- +- StringRef dylibName; +- uint64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel +- bool reexport = false; +- std::vector reexported; +-}; +- +-// .a file +-class ArchiveFile : public InputFile { +-public: +- explicit ArchiveFile(std::unique_ptr &&file); +- static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; } +- void fetch(const llvm::object::Archive::Symbol &sym); +- +-private: +- std::unique_ptr file; +- // Keep track of children fetched from the archive by tracking +- // which address offsets have been fetched already. +- llvm::DenseSet seen; +-}; +- +-extern std::vector inputFiles; +- +-llvm::Optional readFile(StringRef path); +- +-} // namespace macho +- +-std::string toString(const macho::InputFile *file); +-} // namespace lld +- +-#endif +diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp +deleted file mode 100644 +index 72d48928305..00000000000 +--- a/lld/MachO/InputSection.cpp ++++ /dev/null +@@ -1,48 +0,0 @@ +-//===- InputSection.cpp ---------------------------------------------------===// +-// +-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +-// See https://llvm.org/LICENSE.txt for license information. +-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +-// +-//===----------------------------------------------------------------------===// +- +-#include "InputSection.h" +-#include "OutputSegment.h" +-#include "Symbols.h" +-#include "Target.h" +-#include "lld/Common/Memory.h" +-#include "llvm/Support/Endian.h" +- +-using namespace llvm; +-using namespace llvm::MachO; +-using namespace llvm::support; +-using namespace lld; +-using namespace lld::macho; +- +-std::vector macho::inputSections; +- +-uint64_t InputSection::getFileOffset() const { +- return parent->fileOff + outSecFileOff; +-} +- +-uint64_t InputSection::getVA() const { return parent->addr + outSecOff; } +- +-void InputSection::writeTo(uint8_t *buf) { +- if (getFileSize() == 0) +- return; +- +- memcpy(buf, data.data(), data.size()); +- +- for (Reloc &r : relocs) { +- uint64_t va = 0; +- if (auto *s = r.target.dyn_cast()) +- va = target->getSymbolVA(*s, r.type); +- else if (auto *isec = r.target.dyn_cast()) +- va = isec->getVA(); +- +- uint64_t val = va + r.addend; +- if (r.pcrel) +- val -= getVA() + r.offset; +- target->relocateOne(buf + r.offset, r, val); +- } +-} +diff --git a/lld/MachO/InputSection.h b/lld/MachO/InputSection.h +deleted file mode 100644 +index 96ae0cbe6ea..00000000000 +--- a/lld/MachO/InputSection.h ++++ /dev/null +@@ -1,74 +0,0 @@ +-//===- InputSection.h -------------------------------------------*- C++ -*-===// +-// +-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +-// See https://llvm.org/LICENSE.txt for license information. +-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLD_MACHO_INPUT_SECTION_H +-#define LLD_MACHO_INPUT_SECTION_H +- +-#include "lld/Common/LLVM.h" +-#include "llvm/ADT/ArrayRef.h" +-#include "llvm/ADT/PointerUnion.h" +-#include "llvm/BinaryFormat/MachO.h" +- +-namespace lld { +-namespace macho { +- +-class InputFile; +-class InputSection; +-class OutputSection; +-class Symbol; +- +-struct Reloc { +- uint8_t type; +- bool pcrel; +- uint8_t length; +- // The offset from the start of the subsection that this relocation belongs +- // to. +- uint32_t offset; +- // Adding this offset to the address of the target symbol or subsection gives +- // the destination that this relocation refers to. +- uint64_t addend; +- llvm::PointerUnion target; +-}; +- +-inline bool isZeroFill(uint8_t flags) { +- return (flags & llvm::MachO::SECTION_TYPE) == llvm::MachO::S_ZEROFILL; +-} +- +-class InputSection { +-public: +- virtual ~InputSection() = default; +- virtual uint64_t getSize() const { return data.size(); } +- virtual uint64_t getFileSize() const { +- return isZeroFill(flags) ? 0 : getSize(); +- } +- uint64_t getFileOffset() const; +- uint64_t getVA() const; +- +- virtual void writeTo(uint8_t *buf); +- +- InputFile *file = nullptr; +- StringRef name; +- StringRef segname; +- +- OutputSection *parent = nullptr; +- uint64_t outSecOff = 0; +- uint64_t outSecFileOff = 0; +- +- uint32_t align = 1; +- uint32_t flags = 0; +- +- ArrayRef data; +- std::vector relocs; +-}; +- +-extern std::vector inputSections; +- +-} // namespace macho +-} // namespace lld +- +-#endif +diff --git a/lld/MachO/MachOStructs.h b/lld/MachO/MachOStructs.h +deleted file mode 100644 +index 69b50ec2317..00000000000 +--- a/lld/MachO/MachOStructs.h ++++ /dev/null +@@ -1,36 +0,0 @@ +-//===- MachOStructs.h -------------------------------------------*- C++ -*-===// +-// +-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +-// See https://llvm.org/LICENSE.txt for license information. +-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +-// +-//===----------------------------------------------------------------------===// +-// +-// This file defines structures used in the MachO object file format. Note that +-// unlike llvm/BinaryFormat/MachO.h, the structs here are defined in terms of +-// endian- and alignment-compatibility wrappers. +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLD_MACHO_MACHO_STRUCTS_H +-#define LLD_MACHO_MACHO_STRUCTS_H +- +-#include "llvm/Support/Endian.h" +- +-namespace lld { +- +-namespace structs { +- +-struct nlist_64 { +- llvm::support::ulittle32_t n_strx; +- uint8_t n_type; +- uint8_t n_sect; +- llvm::support::ulittle16_t n_desc; +- llvm::support::ulittle64_t n_value; +-}; +- +-} // namespace structs +- +-} // namespace lld +- +-#endif +diff --git a/lld/MachO/MergedOutputSection.cpp b/lld/MachO/MergedOutputSection.cpp +deleted file mode 100644 +index 2d0be253834..00000000000 +--- a/lld/MachO/MergedOutputSection.cpp ++++ /dev/null +@@ -1,74 +0,0 @@ +-//===- OutputSection.cpp --------------------------------------------------===// +-// +-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +-// See https://llvm.org/LICENSE.txt for license information. +-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +-// +-//===----------------------------------------------------------------------===// +- +-#include "MergedOutputSection.h" +-#include "lld/Common/ErrorHandler.h" +-#include "lld/Common/Memory.h" +-#include "llvm/BinaryFormat/MachO.h" +- +-using namespace llvm; +-using namespace llvm::MachO; +-using namespace lld; +-using namespace lld::macho; +- +-void MergedOutputSection::mergeInput(InputSection *input) { +- if (inputs.empty()) { +- align = input->align; +- flags = input->flags; +- } else { +- mergeFlags(input->flags); +- align = std::max(align, input->align); +- } +- +- inputs.push_back(input); +- input->parent = this; +-} +- +-void MergedOutputSection::finalize() { +- uint64_t isecAddr = addr; +- uint64_t isecFileOff = fileOff; +- for (InputSection *isec : inputs) { +- isecAddr = alignTo(isecAddr, isec->align); +- isecFileOff = alignTo(isecFileOff, isec->align); +- isec->outSecOff = isecAddr - addr; +- isec->outSecFileOff = isecFileOff - fileOff; +- isecAddr += isec->getSize(); +- isecFileOff += isec->getFileSize(); +- } +- size = isecAddr - addr; +- fileSize = isecFileOff - fileOff; +-} +- +-void MergedOutputSection::writeTo(uint8_t *buf) const { +- for (InputSection *isec : inputs) { +- isec->writeTo(buf + isec->outSecFileOff); +- } +-} +- +-// TODO: this is most likely wrong; reconsider how section flags +-// are actually merged. The logic presented here was written without +-// any form of informed research. +-void MergedOutputSection::mergeFlags(uint32_t inputFlags) { +- uint8_t sectionFlag = MachO::SECTION_TYPE & inputFlags; +- if (sectionFlag != (MachO::SECTION_TYPE & flags)) +- error("Cannot add merge section; inconsistent type flags " + +- Twine(sectionFlag)); +- +- uint32_t inconsistentFlags = +- MachO::S_ATTR_DEBUG | MachO::S_ATTR_STRIP_STATIC_SYMS | +- MachO::S_ATTR_NO_DEAD_STRIP | MachO::S_ATTR_LIVE_SUPPORT; +- if ((inputFlags ^ flags) & inconsistentFlags) +- error("Cannot add merge section; cannot merge inconsistent flags"); +- +- // Negate pure instruction presence if any section isn't pure. +- uint32_t pureMask = ~MachO::S_ATTR_PURE_INSTRUCTIONS | (inputFlags & flags); +- +- // Merge the rest +- flags |= inputFlags; +- flags &= pureMask; +-} +diff --git a/lld/MachO/MergedOutputSection.h b/lld/MachO/MergedOutputSection.h +deleted file mode 100644 +index 279a7e0f75c..00000000000 +--- a/lld/MachO/MergedOutputSection.h ++++ /dev/null +@@ -1,56 +0,0 @@ +-//===- OutputSection.h ------------------------------------------*- C++ -*-===// +-// +-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +-// See https://llvm.org/LICENSE.txt for license information. +-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef LLD_MACHO_MERGED_OUTPUT_SECTION_H +-#define LLD_MACHO_MERGED_OUTPUT_SECTION_H +- +-#include "InputSection.h" +-#include "OutputSection.h" +-#include "lld/Common/LLVM.h" +-#include "llvm/ADT/MapVector.h" +- +-namespace lld { +-namespace macho { +- +-// Linking multiple files will inevitably mean resolving sections in different +-// files that are labeled with the same segment and section name. This class +-// contains all such sections and writes the data from each section sequentially +-// in the final binary. +-class MergedOutputSection : public OutputSection { +-public: +- MergedOutputSection(StringRef name) : OutputSection(MergedKind, name) {} +- +- const InputSection *firstSection() const { return inputs.front(); } +- const InputSection *lastSection() const { return inputs.back(); } +- +- // These accessors will only be valid after finalizing the section +- uint64_t getSize() const override { return size; } +- uint64_t getFileSize() const override { return fileSize; } +- +- void mergeInput(InputSection *input); +- void finalize() override; +- +- void writeTo(uint8_t *buf) const override; +- +- std::vector inputs; +- +- static bool classof(const OutputSection *sec) { +- return sec->kind() == MergedKind; +- } +- +-private: +- void mergeFlags(uint32_t inputFlags); +- +- size_t size = 0; +- uint64_t fileSize = 0; +-}; +- +-} // namespace macho +-} // namespace lld +- +-#endif +diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td +deleted file mode 100644 +index 1e42542b9ac..00000000000 +--- a/lld/MachO/Options.td ++++ /dev/null +@@ -1,1297 +0,0 @@ +-include "llvm/Option/OptParser.td" +- +-def help : Flag<["-", "--"], "help">; +-def help_hidden : Flag<["--"], "help-hidden">, +- HelpText<"Display help for hidden options">; +- +-// This is a complete Options.td compiled from Apple's ld(1) manpage +-// dated 2018-03-07 and cross checked with ld64 source code in repo +-// https://github.com/apple-opensource/ld64 at git tag "512.4" dated +-// 2018-03-18. +- +-// Flags<[HelpHidden]> marks options that are not yet ported to lld, +-// and serve as a scoreboard for annotating our progress toward +-// implementing ld64 options in lld. As you add implementions to +-// Driver.cpp, please remove the hidden flag here. +- +-def grp_kind : OptionGroup<"kind">, HelpText<"OUTPUT KIND">; +- +-def execute : Flag<["-"], "execute">, +- HelpText<"Produce a main executable (default)">, +- Flags<[HelpHidden]>, +- Group; +-def dylib : Flag<["-"], "dylib">, +- HelpText<"Produce a shared library">, +- Group; +-def bundle : Flag<["-"], "bundle">, +- HelpText<"Produce a bundle">, +- Flags<[HelpHidden]>, +- Group; +-def r : Flag<["-"], "r">, +- HelpText<"Merge multiple object files into one, retaining relocations">, +- Flags<[HelpHidden]>, +- Group; +-def dylinker : Flag<["-"], "dylinker">, +- HelpText<"Produce a dylinker only used when building dyld">, +- Flags<[HelpHidden]>, +- Group; +-def dynamic : Flag<["-"], "dynamic">, +- HelpText<"Link dynamically (default)">, +- Flags<[HelpHidden]>, +- Group; +-def static : Flag<["-"], "static">, +- HelpText<"Link statically">, +- Flags<[HelpHidden]>, +- Group; +-def preload : Flag<["-"], "preload">, +- HelpText<"Produce an unsegmented binary for embedded systems">, +- Flags<[HelpHidden]>, +- Group; +-def arch : Separate<["-"], "arch">, +- MetaVarName<"">, +- HelpText<"The architecture (e.g. ppc, ppc64, i386, x86_64)">, +- Group; +-def o : Separate<["-"], "o">, +- MetaVarName<"">, +- HelpText<"The name of the output file (default: `a.out')">, +- Group; +- +-def grp_libs : OptionGroup<"libs">, HelpText<"LIBRARIES">; +- +-def l : Joined<["-"], "l">, +- MetaVarName<"">, +- HelpText<"Search for lib.dylib or lib.a on the library search path">, +- Group; +-def weak_l : Joined<["-"], "weak-l">, +- MetaVarName<"">, +- HelpText<"Like -l, but mark library and its references as weak imports">, +- Flags<[HelpHidden]>, +- Group; +-def weak_library : Separate<["-"], "weak_library">, +- MetaVarName<"">, +- HelpText<"Like bare , but mark library and its references as weak imports">, +- Flags<[HelpHidden]>, +- Group; +-def reexport_l : Joined<["-"], "reexport-l">, +- MetaVarName<"">, +- HelpText<"Like -l, but export all symbols of from newly created library">, +- Flags<[HelpHidden]>, +- Group; +-def reexport_library : Separate<["-"], "reexport_library">, +- MetaVarName<"">, +- HelpText<"Like bare , but export all symbols of from newly created library">, +- Flags<[HelpHidden]>, +- Group; +-def upward_l : Joined<["-"], "upward-l">, +- MetaVarName<"">, +- HelpText<"Like -l, but specify dylib as an upward dependency">, +- Flags<[HelpHidden]>, +- Group; +-def upward_library : Separate<["-"], "upward_library">, +- MetaVarName<"">, +- HelpText<"Like bare , but specify dylib as an upward dependency">, +- Flags<[HelpHidden]>, +- Group; +-def L : JoinedOrSeparate<["-"], "L">, +- MetaVarName<"">, +- HelpText<"Add dir to the library search path">, +- Group; +-def Z : Flag<["-"], "Z">, +- HelpText<"Remove standard directories from the library and framework search paths">, +- Group; +-def syslibroot : Separate<["-"], "syslibroot">, +- MetaVarName<"">, +- HelpText<"Prepend to all library and framework search paths">, +- Flags<[HelpHidden]>, +- Group; +-def search_paths_first : Flag<["-"], "search_paths_first">, +- HelpText<"Search for lib.dylib and lib.a at each step in traversing search path (default for Xcode 4 and later)">, +- Flags<[HelpHidden]>, +- Group; +-def search_dylibs_first : Flag<["-"], "search_dylibs_first">, +- HelpText<"Search for lib.dylib on first pass, then for lib.a on second pass through search path (default for Xcode 3 and earlier)">, +- Flags<[HelpHidden]>, +- Group; +-def framework : Separate<["-"], "framework">, +- MetaVarName<"">, +- HelpText<"Search for .framework/ on the framework search path">, +- Flags<[HelpHidden]>, +- Group; +-def weak_framework : Separate<["-"], "weak_framework">, +- MetaVarName<"">, +- HelpText<"Like -framework , but mark framework and its references as weak imports">, +- Flags<[HelpHidden]>, +- Group; +-def reexport_framework : Separate<["-"], "reexport_framework">, +- MetaVarName<"">, +- HelpText<"Like -framework , but export all symbols of from the newly created library">, +- Flags<[HelpHidden]>, +- Group; +-def upward_framework : Separate<["-"], "upward_framework">, +- MetaVarName<"">, +- HelpText<"Like -framework , but specify the framework as an upward dependency">, +- Flags<[HelpHidden]>, +- Group; +-def F : JoinedOrSeparate<["-"], "F">, +- MetaVarName<"">, +- HelpText<"Add dir to the framework search path">, +- Flags<[HelpHidden]>, +- Group; +-def all_load : Flag<["-"], "all_load">, +- HelpText<"Load all members of all static archive libraries">, +- Flags<[HelpHidden]>, +- Group; +-def ObjC : Flag<["-"], "ObjC">, +- HelpText<"Load all members of static archives that are an Objective-C class or category.">, +- Flags<[HelpHidden]>, +- Group; +-def force_load : Separate<["-"], "force_load">, +- MetaVarName<"">, +- HelpText<"Load all members static archive library at ">, +- Flags<[HelpHidden]>, +- Group; +- +-def grp_content : OptionGroup<"content">, HelpText<"ADDITIONAL CONTENT">; +- +-def sectcreate : MultiArg<["-"], "sectcreate", 3>, +- MetaVarName<"
">, +- HelpText<"Create
in from the contents of ">, +- Flags<[HelpHidden]>, +- Group; +-def segcreate : MultiArg<["-"], "segcreate", 3>, +- MetaVarName<"
">, +- Alias, +- HelpText<"Alias for -sectcreate">, +- Flags<[HelpHidden]>, +- Group; +-def filelist : Separate<["-"], "filelist">, +- MetaVarName<"">, +- HelpText<"Read names of files to link from ">, +- Flags<[HelpHidden]>, +- Group; +-def dtrace : Separate<["-"], "dtrace">, +- MetaVarName<"