diff --git a/.gitignore b/.gitignore index f2bd1f1..ad335a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -SOURCES/lld-11.0.1.src.tar.xz +SOURCES/lld-12.0.1.src.tar.xz +SOURCES/tstellar-gpg-key.asc diff --git a/.lld.metadata b/.lld.metadata index 6eb3909..184b2a9 100644 --- a/.lld.metadata +++ b/.lld.metadata @@ -1 +1,2 @@ -ef1679dd56bdab3fe8b2bb07721b0d99ee43ff5d SOURCES/lld-11.0.1.src.tar.xz +3b7e4908f6cf3a51590e37b4194180582cc1c32c SOURCES/lld-12.0.1.src.tar.xz +b8d2648a01d36ed0186fd2c5af325fd28797f9a0 SOURCES/tstellar-gpg-key.asc diff --git a/SOURCES/0001-CMake-Check-for-gtest-headers-even-if-lit.py-is-not-.patch b/SOURCES/0001-PATCH-lld-CMake-Check-for-gtest-headers-even-if-lit..patch similarity index 74% rename from SOURCES/0001-CMake-Check-for-gtest-headers-even-if-lit.py-is-not-.patch rename to SOURCES/0001-PATCH-lld-CMake-Check-for-gtest-headers-even-if-lit..patch index c4af14d..ea10149 100644 --- a/SOURCES/0001-CMake-Check-for-gtest-headers-even-if-lit.py-is-not-.patch +++ b/SOURCES/0001-PATCH-lld-CMake-Check-for-gtest-headers-even-if-lit..patch @@ -1,19 +1,20 @@ -From e5bdf4580677da063abe8d3880fbab9eaa7a7efe Mon Sep 17 00:00:00 2001 +From 760568cd24acd6ae9083b0dfea2c7c0ea6f0adc2 Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Thu, 30 Aug 2018 08:53:56 -0700 -Subject: [PATCH] CMake: Check for gtest headers even if lit.py is not present +Subject: [PATCH 1/2] [PATCH][lld] CMake: Check for gtest headers even if + lit.py is not present This makes it possible to build the unittests even withotu a full checkout of the llvm source tree. --- - CMakeLists.txt | 15 +++++++++------ + lld/CMakeLists.txt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) -diff --git a/CMakeLists.txt b/CMakeLists.txt -index e2fbdbf..c9b2927 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -75,6 +75,15 @@ Please install Python or specify the PYTHON_EXECUTABLE CMake variable.") +diff --git a/lld/CMakeLists.txt b/lld/CMakeLists.txt +index d4e561b..a7406d1c 100644 +--- a/lld/CMakeLists.txt ++++ b/lld/CMakeLists.txt +@@ -65,6 +65,15 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) set(LLVM_UTILS_PROVIDED ON) endif() @@ -29,7 +30,7 @@ index e2fbdbf..c9b2927 100644 if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) # Note: path not really used, except for checking if lit was found set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py) -@@ -84,12 +93,6 @@ Please install Python or specify the PYTHON_EXECUTABLE CMake variable.") +@@ -74,12 +83,6 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) set(LLVM_UTILS_PROVIDED ON) set(LLD_TEST_DEPS FileCheck not) endif() diff --git a/SOURCES/0001-Revert-lld-Initial-commit-for-new-Mach-O-backend.patch b/SOURCES/0001-Revert-lld-Initial-commit-for-new-Mach-O-backend.patch deleted file mode 100644 index 597ebb9..0000000 --- a/SOURCES/0001-Revert-lld-Initial-commit-for-new-Mach-O-backend.patch +++ /dev/null @@ -1,7986 +0,0 @@ -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<"