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<"