diff options
Diffstat (limited to 'ELF')
64 files changed, 8069 insertions, 6056 deletions
diff --git a/ELF/AArch64ErrataFix.cpp b/ELF/AArch64ErrataFix.cpp new file mode 100644 index 000000000000..6cc68cc08e10 --- /dev/null +++ b/ELF/AArch64ErrataFix.cpp @@ -0,0 +1,648 @@ +//===- AArch64ErrataFix.cpp -----------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This file implements Section Patching for the purpose of working around +// errata in CPUs. The general principle is that an erratum sequence of one or +// more instructions is detected in the instruction stream, one of the +// instructions in the sequence is replaced with a branch to a patch sequence +// of replacement instructions. At the end of the replacement sequence the +// patch branches back to the instruction stream. + +// This technique is only suitable for fixing an erratum when: +// - There is a set of necessary conditions required to trigger the erratum that +// can be detected at static link time. +// - There is a set of replacement instructions that can be used to remove at +// least one of the necessary conditions that trigger the erratum. +// - We can overwrite an instruction in the erratum sequence with a branch to +// the replacement sequence. +// - We can place the replacement sequence within range of the branch. + +// FIXME: +// - The implementation here only supports one patch, the AArch64 Cortex-53 +// errata 843419 that affects r0p0, r0p1, r0p2 and r0p4 versions of the core. +// To keep the initial version simple there is no support for multiple +// architectures or selection of different patches. +//===----------------------------------------------------------------------===// + +#include "AArch64ErrataFix.h" +#include "Config.h" +#include "LinkerScript.h" +#include "OutputSections.h" +#include "Relocations.h" +#include "Strings.h" +#include "Symbols.h" +#include "SyntheticSections.h" +#include "Target.h" +#include "lld/Common/Memory.h" + +#include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> + +using namespace llvm; +using namespace llvm::ELF; +using namespace llvm::object; +using namespace llvm::support::endian; + +using namespace lld; +using namespace lld::elf; + +// Helper functions to identify instructions and conditions needed to trigger +// the Cortex-A53-843419 erratum. + +// ADRP +// | 1 | immlo (2) | 1 | 0 0 0 0 | immhi (19) | Rd (5) | +static bool isADRP(uint32_t Instr) { + return (Instr & 0x9f000000) == 0x90000000; +} + +// Load and store bit patterns from ARMv8-A ARM ARM. +// Instructions appear in order of appearance starting from table in +// C4.1.3 Loads and Stores. + +// All loads and stores have 1 (at bit postion 27), (0 at bit position 25). +// | op0 x op1 (2) | 1 op2 0 op3 (2) | x | op4 (5) | xxxx | op5 (2) | x (10) | +static bool isLoadStoreClass(uint32_t Instr) { + return (Instr & 0x0a000000) == 0x08000000; +} + +// LDN/STN multiple no offset +// | 0 Q 00 | 1100 | 0 L 00 | 0000 | opcode (4) | size (2) | Rn (5) | Rt (5) | +// LDN/STN multiple post-indexed +// | 0 Q 00 | 1100 | 1 L 0 | Rm (5)| opcode (4) | size (2) | Rn (5) | Rt (5) | +// L == 0 for stores. + +// Utility routine to decode opcode field of LDN/STN multiple structure +// instructions to find the ST1 instructions. +// opcode == 0010 ST1 4 registers. +// opcode == 0110 ST1 3 registers. +// opcode == 0111 ST1 1 register. +// opcode == 1010 ST1 2 registers. +static bool isST1MultipleOpcode(uint32_t Instr) { + return (Instr & 0x0000f000) == 0x00002000 || + (Instr & 0x0000f000) == 0x00006000 || + (Instr & 0x0000f000) == 0x00007000 || + (Instr & 0x0000f000) == 0x0000a000; +} + +static bool isST1Multiple(uint32_t Instr) { + return (Instr & 0xbfff0000) == 0x0c000000 && isST1MultipleOpcode(Instr); +} + +// Writes to Rn (writeback). +static bool isST1MultiplePost(uint32_t Instr) { + return (Instr & 0xbfe00000) == 0x0c800000 && isST1MultipleOpcode(Instr); +} + +// LDN/STN single no offset +// | 0 Q 00 | 1101 | 0 L R 0 | 0000 | opc (3) S | size (2) | Rn (5) | Rt (5)| +// LDN/STN single post-indexed +// | 0 Q 00 | 1101 | 1 L R | Rm (5) | opc (3) S | size (2) | Rn (5) | Rt (5)| +// L == 0 for stores + +// Utility routine to decode opcode field of LDN/STN single structure +// instructions to find the ST1 instructions. +// R == 0 for ST1 and ST3, R == 1 for ST2 and ST4. +// opcode == 000 ST1 8-bit. +// opcode == 010 ST1 16-bit. +// opcode == 100 ST1 32 or 64-bit (Size determines which). +static bool isST1SingleOpcode(uint32_t Instr) { + return (Instr & 0x0040e000) == 0x00000000 || + (Instr & 0x0040e000) == 0x00004000 || + (Instr & 0x0040e000) == 0x00008000; +} + +static bool isST1Single(uint32_t Instr) { + return (Instr & 0xbfff0000) == 0x0d000000 && isST1SingleOpcode(Instr); +} + +// Writes to Rn (writeback). +static bool isST1SinglePost(uint32_t Instr) { + return (Instr & 0xbfe00000) == 0x0d800000 && isST1SingleOpcode(Instr); +} + +static bool isST1(uint32_t Instr) { + return isST1Multiple(Instr) || isST1MultiplePost(Instr) || + isST1Single(Instr) || isST1SinglePost(Instr); +} + +// Load/store exclusive +// | size (2) 00 | 1000 | o2 L o1 | Rs (5) | o0 | Rt2 (5) | Rn (5) | Rt (5) | +// L == 0 for Stores. +static bool isLoadStoreExclusive(uint32_t Instr) { + return (Instr & 0x3f000000) == 0x08000000; +} + +static bool isLoadExclusive(uint32_t Instr) { + return (Instr & 0x3f400000) == 0x08400000; +} + +// Load register literal +// | opc (2) 01 | 1 V 00 | imm19 | Rt (5) | +static bool isLoadLiteral(uint32_t Instr) { + return (Instr & 0x3b000000) == 0x18000000; +} + +// Load/store no-allocate pair +// (offset) +// | opc (2) 10 | 1 V 00 | 0 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | +// L == 0 for stores. +// Never writes to register +static bool isSTNP(uint32_t Instr) { + return (Instr & 0x3bc00000) == 0x28000000; +} + +// Load/store register pair +// (post-indexed) +// | opc (2) 10 | 1 V 00 | 1 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | +// L == 0 for stores, V == 0 for Scalar, V == 1 for Simd/FP +// Writes to Rn. +static bool isSTPPost(uint32_t Instr) { + return (Instr & 0x3bc00000) == 0x28800000; +} + +// (offset) +// | opc (2) 10 | 1 V 01 | 0 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | +static bool isSTPOffset(uint32_t Instr) { + return (Instr & 0x3bc00000) == 0x29000000; +} + +// (pre-index) +// | opc (2) 10 | 1 V 01 | 1 L | imm7 | Rt2 (5) | Rn (5) | Rt (5) | +// Writes to Rn. +static bool isSTPPre(uint32_t Instr) { + return (Instr & 0x3bc00000) == 0x29800000; +} + +static bool isSTP(uint32_t Instr) { + return isSTPPost(Instr) || isSTPOffset(Instr) || isSTPPre(Instr); +} + +// Load/store register (unscaled immediate) +// | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 00 | Rn (5) | Rt (5) | +// V == 0 for Scalar, V == 1 for Simd/FP. +static bool isLoadStoreUnscaled(uint32_t Instr) { + return (Instr & 0x3b000c00) == 0x38000000; +} + +// Load/store register (immediate post-indexed) +// | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 01 | Rn (5) | Rt (5) | +static bool isLoadStoreImmediatePost(uint32_t Instr) { + return (Instr & 0x3b200c00) == 0x38000400; +} + +// Load/store register (unprivileged) +// | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 10 | Rn (5) | Rt (5) | +static bool isLoadStoreUnpriv(uint32_t Instr) { + return (Instr & 0x3b200c00) == 0x38000800; +} + +// Load/store register (immediate pre-indexed) +// | size (2) 11 | 1 V 00 | opc (2) 0 | imm9 | 11 | Rn (5) | Rt (5) | +static bool isLoadStoreImmediatePre(uint32_t Instr) { + return (Instr & 0x3b200c00) == 0x38000c00; +} + +// Load/store register (register offset) +// | size (2) 11 | 1 V 00 | opc (2) 1 | Rm (5) | option (3) S | 10 | Rn | Rt | +static bool isLoadStoreRegisterOff(uint32_t Instr) { + return (Instr & 0x3b200c00) == 0x38200800; +} + +// Load/store register (unsigned immediate) +// | size (2) 11 | 1 V 01 | opc (2) | imm12 | Rn (5) | Rt (5) | +static bool isLoadStoreRegisterUnsigned(uint32_t Instr) { + return (Instr & 0x3b000000) == 0x39000000; +} + +// Rt is always in bit position 0 - 4. +static uint32_t getRt(uint32_t Instr) { return (Instr & 0x1f); } + +// Rn is always in bit position 5 - 9. +static uint32_t getRn(uint32_t Instr) { return (Instr >> 5) & 0x1f; } + +// C4.1.2 Branches, Exception Generating and System instructions +// | op0 (3) 1 | 01 op1 (4) | x (22) | +// op0 == 010 101 op1 == 0xxx Conditional Branch. +// op0 == 110 101 op1 == 1xxx Unconditional Branch Register. +// op0 == x00 101 op1 == xxxx Unconditional Branch immediate. +// op0 == x01 101 op1 == 0xxx Compare and branch immediate. +// op0 == x01 101 op1 == 1xxx Test and branch immediate. +static bool isBranch(uint32_t Instr) { + return ((Instr & 0xfe000000) == 0xd6000000) || // Cond branch. + ((Instr & 0xfe000000) == 0x54000000) || // Uncond branch reg. + ((Instr & 0x7c000000) == 0x14000000) || // Uncond branch imm. + ((Instr & 0x7c000000) == 0x34000000); // Compare and test branch. +} + +static bool isV8SingleRegisterNonStructureLoadStore(uint32_t Instr) { + return isLoadStoreUnscaled(Instr) || isLoadStoreImmediatePost(Instr) || + isLoadStoreUnpriv(Instr) || isLoadStoreImmediatePre(Instr) || + isLoadStoreRegisterOff(Instr) || isLoadStoreRegisterUnsigned(Instr); +} + +// Note that this function refers to v8.0 only and does not include the +// additional load and store instructions added for in later revisions of +// the architecture such as the Atomic memory operations introduced +// in v8.1. +static bool isV8NonStructureLoad(uint32_t Instr) { + if (isLoadExclusive(Instr)) + return true; + if (isLoadLiteral(Instr)) + return true; + else if (isV8SingleRegisterNonStructureLoadStore(Instr)) { + // For Load and Store single register, Loads are derived from a + // combination of the Size, V and Opc fields. + uint32_t Size = (Instr >> 30) & 0xff; + uint32_t V = (Instr >> 26) & 0x1; + uint32_t Opc = (Instr >> 22) & 0x3; + // For the load and store instructions that we are decoding. + // Opc == 0 are all stores. + // Opc == 1 with a couple of exceptions are loads. The exceptions are: + // Size == 00 (0), V == 1, Opc == 10 (2) which is a store and + // Size == 11 (3), V == 0, Opc == 10 (2) which is a prefetch. + return Opc != 0 && !(Size == 0 && V == 1 && Opc == 2) && + !(Size == 3 && V == 0 && Opc == 2); + } + return false; +} + +// The following decode instructions are only complete up to the instructions +// needed for errata 843419. + +// Instruction with writeback updates the index register after the load/store. +static bool hasWriteback(uint32_t Instr) { + return isLoadStoreImmediatePre(Instr) || isLoadStoreImmediatePost(Instr) || + isSTPPre(Instr) || isSTPPost(Instr) || isST1SinglePost(Instr) || + isST1MultiplePost(Instr); +} + +// For the load and store class of instructions, a load can write to the +// destination register, a load and a store can write to the base register when +// the instruction has writeback. +static bool doesLoadStoreWriteToReg(uint32_t Instr, uint32_t Reg) { + return (isV8NonStructureLoad(Instr) && getRt(Instr) == Reg) || + (hasWriteback(Instr) && getRn(Instr) == Reg); +} + +// Scanner for Cortex-A53 errata 843419 +// Full details are available in the Cortex A53 MPCore revision 0 Software +// Developers Errata Notice (ARM-EPM-048406). +// +// The instruction sequence that triggers the erratum is common in compiled +// AArch64 code, however it is sensitive to the offset of the sequence within +// a 4k page. This means that by scanning and fixing the patch after we have +// assigned addresses we only need to disassemble and fix instances of the +// sequence in the range of affected offsets. +// +// In summary the erratum conditions are a series of 4 instructions: +// 1.) An ADRP instruction that writes to register Rn with low 12 bits of +// address of instruction either 0xff8 or 0xffc. +// 2.) A load or store instruction that can be: +// - A single register load or store, of either integer or vector registers. +// - An STP or STNP, of either integer or vector registers. +// - An Advanced SIMD ST1 store instruction. +// - Must not write to Rn, but may optionally read from it. +// 3.) An optional instruction that is not a branch and does not write to Rn. +// 4.) A load or store from the Load/store register (unsigned immediate) class +// that uses Rn as the base address register. +// +// Note that we do not attempt to scan for Sequence 2 as described in the +// Software Developers Errata Notice as this has been assessed to be extremely +// unlikely to occur in compiled code. This matches gold and ld.bfd behavior. + +// Return true if the Instruction sequence Adrp, Instr2, and Instr4 match +// the erratum sequence. The Adrp, Instr2 and Instr4 correspond to 1.), 2.), +// and 4.) in the Scanner for Cortex-A53 errata comment above. +static bool is843419ErratumSequence(uint32_t Instr1, uint32_t Instr2, + uint32_t Instr4) { + if (!isADRP(Instr1)) + return false; + + uint32_t Rn = getRt(Instr1); + return isLoadStoreClass(Instr2) && + (isLoadStoreExclusive(Instr2) || isLoadLiteral(Instr2) || + isV8SingleRegisterNonStructureLoadStore(Instr2) || isSTP(Instr2) || + isSTNP(Instr2) || isST1(Instr2)) && + !doesLoadStoreWriteToReg(Instr2, Rn) && + isLoadStoreRegisterUnsigned(Instr4) && getRn(Instr4) == Rn; +} + +// Scan the instruction sequence starting at Offset Off from the base of +// InputSection IS. We update Off in this function rather than in the caller as +// we can skip ahead much further into the section when we know how many +// instructions we've scanned. +// Return the offset of the load or store instruction in IS that we want to +// patch or 0 if no patch required. +static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off, + uint64_t Limit) { + uint64_t ISAddr = IS->getParent()->Addr + IS->OutSecOff; + + // Advance Off so that (ISAddr + Off) modulo 0x1000 is at least 0xff8. + uint64_t InitialPageOff = (ISAddr + Off) & 0xfff; + if (InitialPageOff < 0xff8) + Off += 0xff8 - InitialPageOff; + + bool OptionalAllowed = Limit - Off > 12; + if (Off >= Limit || Limit - Off < 12) { + // Need at least 3 4-byte sized instructions to trigger erratum. + Off = Limit; + return 0; + } + + uint64_t PatchOff = 0; + const uint8_t *Buf = IS->Data.begin(); + const uint32_t *InstBuf = reinterpret_cast<const uint32_t *>(Buf + Off); + uint32_t Instr1 = *InstBuf++; + uint32_t Instr2 = *InstBuf++; + uint32_t Instr3 = *InstBuf++; + if (is843419ErratumSequence(Instr1, Instr2, Instr3)) { + PatchOff = Off + 8; + } else if (OptionalAllowed && !isBranch(Instr3)) { + uint32_t Instr4 = *InstBuf++; + if (is843419ErratumSequence(Instr1, Instr2, Instr4)) + PatchOff = Off + 12; + } + if (((ISAddr + Off) & 0xfff) == 0xff8) + Off += 4; + else + Off += 0xffc; + return PatchOff; +} + +class lld::elf::Patch843419Section : public SyntheticSection { +public: + Patch843419Section(InputSection *P, uint64_t Off); + + void writeTo(uint8_t *Buf) override; + + size_t getSize() const override { return 8; } + + uint64_t getLDSTAddr() const; + + // The Section we are patching. + const InputSection *Patchee; + // The offset of the instruction in the Patchee section we are patching. + uint64_t PatcheeOffset; + // A label for the start of the Patch that we can use as a relocation target. + Symbol *PatchSym; +}; + +lld::elf::Patch843419Section::Patch843419Section(InputSection *P, uint64_t Off) + : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 4, + ".text.patch"), + Patchee(P), PatcheeOffset(Off) { + this->Parent = P->getParent(); + PatchSym = addSyntheticLocal( + Saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0, + getSize(), this); + addSyntheticLocal(Saver.save("$x"), STT_NOTYPE, 0, 0, this); +} + +uint64_t lld::elf::Patch843419Section::getLDSTAddr() const { + return Patchee->getParent()->Addr + Patchee->OutSecOff + PatcheeOffset; +} + +void lld::elf::Patch843419Section::writeTo(uint8_t *Buf) { + // Copy the instruction that we will be replacing with a branch in the + // Patchee Section. + write32le(Buf, read32le(Patchee->Data.begin() + PatcheeOffset)); + + // Apply any relocation transferred from the original PatcheeSection. + // For a SyntheticSection Buf already has OutSecOff added, but relocateAlloc + // also adds OutSecOff so we need to subtract to avoid double counting. + this->relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + getSize()); + + // Return address is the next instruction after the one we have just copied. + uint64_t S = getLDSTAddr() + 4; + uint64_t P = PatchSym->getVA() + 4; + Target->relocateOne(Buf + 4, R_AARCH64_JUMP26, S - P); +} + +void AArch64Err843419Patcher::init() { + // The AArch64 ABI permits data in executable sections. We must avoid scanning + // this data as if it were instructions to avoid false matches. We use the + // mapping symbols in the InputObjects to identify this data, caching the + // results in SectionMap so we don't have to recalculate it each pass. + + // The ABI Section 4.5.4 Mapping symbols; defines local symbols that describe + // half open intervals [Symbol Value, Next Symbol Value) of code and data + // within sections. If there is no next symbol then the half open interval is + // [Symbol Value, End of section). The type, code or data, is determined by + // the mapping symbol name, $x for code, $d for data. + auto IsCodeMapSymbol = [](const Symbol *B) { + return B->getName() == "$x" || B->getName().startswith("$x."); + }; + auto IsDataMapSymbol = [](const Symbol *B) { + return B->getName() == "$d" || B->getName().startswith("$d."); + }; + + // Collect mapping symbols for every executable InputSection. + for (InputFile *File : ObjectFiles) { + auto *F = cast<ObjFile<ELF64LE>>(File); + for (Symbol *B : F->getLocalSymbols()) { + auto *Def = dyn_cast<Defined>(B); + if (!Def) + continue; + if (!IsCodeMapSymbol(Def) && !IsDataMapSymbol(Def)) + continue; + if (auto *Sec = dyn_cast<InputSection>(Def->Section)) + if (Sec->Flags & SHF_EXECINSTR) + SectionMap[Sec].push_back(Def); + } + } + // For each InputSection make sure the mapping symbols are in sorted in + // ascending order and free from consecutive runs of mapping symbols with + // the same type. For example we must remove the redundant $d.1 from $x.0 + // $d.0 $d.1 $x.1. + for (auto &KV : SectionMap) { + std::vector<const Defined *> &MapSyms = KV.second; + if (MapSyms.size() <= 1) + continue; + std::stable_sort( + MapSyms.begin(), MapSyms.end(), + [](const Defined *A, const Defined *B) { return A->Value < B->Value; }); + MapSyms.erase( + std::unique(MapSyms.begin(), MapSyms.end(), + [=](const Defined *A, const Defined *B) { + return (IsCodeMapSymbol(A) && IsCodeMapSymbol(B)) || + (IsDataMapSymbol(A) && IsDataMapSymbol(B)); + }), + MapSyms.end()); + } + Initialized = true; +} + +// Insert the PatchSections we have created back into the +// InputSectionDescription. As inserting patches alters the addresses of +// InputSections that follow them, we try and place the patches after all the +// executable sections, although we may need to insert them earlier if the +// InputSectionDescription is larger than the maximum branch range. +void AArch64Err843419Patcher::insertPatches( + InputSectionDescription &ISD, std::vector<Patch843419Section *> &Patches) { + uint64_t ISLimit; + uint64_t PrevISLimit = ISD.Sections.front()->OutSecOff; + uint64_t PatchUpperBound = PrevISLimit + Target->ThunkSectionSpacing; + + // Set the OutSecOff of patches to the place where we want to insert them. + // We use a similar strategy to Thunk placement. Place patches roughly + // every multiple of maximum branch range. + auto PatchIt = Patches.begin(); + auto PatchEnd = Patches.end(); + for (const InputSection *IS : ISD.Sections) { + ISLimit = IS->OutSecOff + IS->getSize(); + if (ISLimit > PatchUpperBound) { + while (PatchIt != PatchEnd) { + if ((*PatchIt)->getLDSTAddr() >= PrevISLimit) + break; + (*PatchIt)->OutSecOff = PrevISLimit; + ++PatchIt; + } + PatchUpperBound = PrevISLimit + Target->ThunkSectionSpacing; + } + PrevISLimit = ISLimit; + } + for (; PatchIt != PatchEnd; ++PatchIt) { + (*PatchIt)->OutSecOff = ISLimit; + } + + // merge all patch sections. We use the OutSecOff assigned above to + // determine the insertion point. This is ok as we only merge into an + // InputSectionDescription once per pass, and at the end of the pass + // assignAddresses() will recalculate all the OutSecOff values. + std::vector<InputSection *> Tmp; + Tmp.reserve(ISD.Sections.size() + Patches.size()); + auto MergeCmp = [](const InputSection *A, const InputSection *B) { + if (A->OutSecOff < B->OutSecOff) + return true; + if (A->OutSecOff == B->OutSecOff && isa<Patch843419Section>(A) && + !isa<Patch843419Section>(B)) + return true; + return false; + }; + std::merge(ISD.Sections.begin(), ISD.Sections.end(), Patches.begin(), + Patches.end(), std::back_inserter(Tmp), MergeCmp); + ISD.Sections = std::move(Tmp); +} + +// Given an erratum sequence that starts at address AdrpAddr, with an +// instruction that we need to patch at PatcheeOffset from the start of +// InputSection IS, create a Patch843419 Section and add it to the +// Patches that we need to insert. +static void implementPatch(uint64_t AdrpAddr, uint64_t PatcheeOffset, + InputSection *IS, + std::vector<Patch843419Section *> &Patches) { + // There may be a relocation at the same offset that we are patching. There + // are three cases that we need to consider. + // Case 1: R_AARCH64_JUMP26 branch relocation. We have already patched this + // instance of the erratum on a previous patch and altered the relocation. We + // have nothing more to do. + // Case 2: A load/store register (unsigned immediate) class relocation. There + // are two of these R_AARCH_LD64_ABS_LO12_NC and R_AARCH_LD64_GOT_LO12_NC and + // they are both absolute. We need to add the same relocation to the patch, + // and replace the relocation with a R_AARCH_JUMP26 branch relocation. + // Case 3: No relocation. We must create a new R_AARCH64_JUMP26 branch + // relocation at the offset. + auto RelIt = std::find_if( + IS->Relocations.begin(), IS->Relocations.end(), + [=](const Relocation &R) { return R.Offset == PatcheeOffset; }); + if (RelIt != IS->Relocations.end() && RelIt->Type == R_AARCH64_JUMP26) + return; + + if (Config->Verbose) + message("detected cortex-a53-843419 erratum sequence starting at " + + utohexstr(AdrpAddr) + " in unpatched output."); + + auto *PS = make<Patch843419Section>(IS, PatcheeOffset); + Patches.push_back(PS); + + auto MakeRelToPatch = [](uint64_t Offset, Symbol *PatchSym) { + return Relocation{R_PC, R_AARCH64_JUMP26, Offset, 0, PatchSym}; + }; + + if (RelIt != IS->Relocations.end()) { + PS->Relocations.push_back( + {RelIt->Expr, RelIt->Type, 0, RelIt->Addend, RelIt->Sym}); + *RelIt = MakeRelToPatch(PatcheeOffset, PS->PatchSym); + } else + IS->Relocations.push_back(MakeRelToPatch(PatcheeOffset, PS->PatchSym)); +} + +// Scan all the instructions in InputSectionDescription, for each instance of +// the erratum sequence create a Patch843419Section. We return the list of +// Patch843419Sections that need to be applied to ISD. +std::vector<Patch843419Section *> +AArch64Err843419Patcher::patchInputSectionDescription( + InputSectionDescription &ISD) { + std::vector<Patch843419Section *> Patches; + for (InputSection *IS : ISD.Sections) { + // LLD doesn't use the erratum sequence in SyntheticSections. + if (isa<SyntheticSection>(IS)) + continue; + // Use SectionMap to make sure we only scan code and not inline data. + // We have already sorted MapSyms in ascending order and removed consecutive + // mapping symbols of the same type. Our range of executable instructions to + // scan is therefore [CodeSym->Value, DataSym->Value) or [CodeSym->Value, + // section size). + std::vector<const Defined *> &MapSyms = SectionMap[IS]; + + auto CodeSym = llvm::find_if(MapSyms, [&](const Defined *MS) { + return MS->getName().startswith("$x"); + }); + + while (CodeSym != MapSyms.end()) { + auto DataSym = std::next(CodeSym); + uint64_t Off = (*CodeSym)->Value; + uint64_t Limit = + (DataSym == MapSyms.end()) ? IS->Data.size() : (*DataSym)->Value; + + while (Off < Limit) { + uint64_t StartAddr = IS->getParent()->Addr + IS->OutSecOff + Off; + if (uint64_t PatcheeOffset = scanCortexA53Errata843419(IS, Off, Limit)) + implementPatch(StartAddr, PatcheeOffset, IS, Patches); + } + if (DataSym == MapSyms.end()) + break; + CodeSym = std::next(DataSym); + } + } + return Patches; +} + +// For each InputSectionDescription make one pass over the executable sections +// looking for the erratum sequence; creating a synthetic Patch843419Section +// for each instance found. We insert these synthetic patch sections after the +// executable code in each InputSectionDescription. +// +// PreConditions: +// The Output and Input Sections have had their final addresses assigned. +// +// PostConditions: +// Returns true if at least one patch was added. The addresses of the +// Ouptut and Input Sections may have been changed. +// Returns false if no patches were required and no changes were made. +bool AArch64Err843419Patcher::createFixes() { + if (Initialized == false) + init(); + + bool AddressesChanged = false; + for (OutputSection *OS : OutputSections) { + if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) + continue; + for (BaseCommand *BC : OS->SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) { + std::vector<Patch843419Section *> Patches = + patchInputSectionDescription(*ISD); + if (!Patches.empty()) { + insertPatches(*ISD, Patches); + AddressesChanged = true; + } + } + } + return AddressesChanged; +} diff --git a/ELF/AArch64ErrataFix.h b/ELF/AArch64ErrataFix.h new file mode 100644 index 000000000000..6c100f25d8af --- /dev/null +++ b/ELF/AArch64ErrataFix.h @@ -0,0 +1,52 @@ +//===- AArch64ErrataFix.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_AARCH64ERRATAFIX_H +#define LLD_ELF_AARCH64ERRATAFIX_H + +#include "lld/Common/LLVM.h" + +#include <map> +#include <vector> + +namespace lld { +namespace elf { + +class Defined; +class InputSection; +struct InputSectionDescription; +class OutputSection; +class Patch843419Section; + +class AArch64Err843419Patcher { +public: + // return true if Patches have been added to the OutputSections. + bool createFixes(); + +private: + std::vector<Patch843419Section *> + patchInputSectionDescription(InputSectionDescription &ISD); + + void insertPatches(InputSectionDescription &ISD, + std::vector<Patch843419Section *> &Patches); + + void init(); + + // A cache of the mapping symbols defined by the InputSecion sorted in order + // of ascending value with redundant symbols removed. These describe + // the ranges of code and data in an executable InputSection. + std::map<InputSection *, std::vector<const Defined *>> SectionMap; + + bool Initialized = false; +}; + +} // namespace elf +} // namespace lld + +#endif diff --git a/ELF/Arch/AArch64.cpp b/ELF/Arch/AArch64.cpp index b26cf0815109..99e9879a6989 100644 --- a/ELF/Arch/AArch64.cpp +++ b/ELF/Arch/AArch64.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" @@ -32,20 +32,23 @@ namespace { class AArch64 final : public TargetInfo { public: AArch64(); - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; - bool isPicRel(uint32_t Type) const override; - void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; + bool isPicRel(RelType Type) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; - bool usesOnlyLowPageBits(uint32_t Type) const override; - void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; - RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const override; + bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; + bool usesOnlyLowPageBits(RelType Type) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr Expr) const override; - void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; - void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; - void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace @@ -66,13 +69,17 @@ AArch64::AArch64() { // It doesn't seem to be documented anywhere, but tls on aarch64 uses variant // 1 of the tls structures and the tcb size is 16. TcbSize = 16; + NeedsThunks = true; + + // See comment in Arch/ARM.cpp for a more detailed explanation of + // ThunkSectionSpacing. For AArch64 the only branches we are permitted to + // Thunk have a range of +/- 128 MiB + ThunkSectionSpacing = (128 * 1024 * 1024) - 0x30000; } -RelExpr AArch64::getRelExpr(uint32_t Type, const SymbolBody &S, +RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { - default: - return R_ABS; case R_AARCH64_TLSDESC_ADR_PAGE21: return R_TLSDESC_PAGE; case R_AARCH64_TLSDESC_LD64_LO12: @@ -92,6 +99,7 @@ RelExpr AArch64::getRelExpr(uint32_t Type, const SymbolBody &S, case R_AARCH64_PREL32: case R_AARCH64_PREL64: case R_AARCH64_ADR_PREL_LO21: + case R_AARCH64_LD_PREL_LO19: return R_PC; case R_AARCH64_ADR_PREL_PG_HI21: return R_PAGE_PC; @@ -103,10 +111,12 @@ RelExpr AArch64::getRelExpr(uint32_t Type, const SymbolBody &S, return R_GOT_PAGE_PC; case R_AARCH64_NONE: return R_NONE; + default: + return R_ABS; } } -RelExpr AArch64::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, +RelExpr AArch64::adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr Expr) const { if (Expr == R_RELAX_TLS_GD_TO_IE) { if (Type == R_AARCH64_TLSDESC_ADR_PAGE21) @@ -116,7 +126,7 @@ RelExpr AArch64::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, return Expr; } -bool AArch64::usesOnlyLowPageBits(uint32_t Type) const { +bool AArch64::usesOnlyLowPageBits(RelType Type) const { switch (Type) { default: return false; @@ -134,11 +144,11 @@ bool AArch64::usesOnlyLowPageBits(uint32_t Type) const { } } -bool AArch64::isPicRel(uint32_t Type) const { +bool AArch64::isPicRel(RelType Type) const { return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64; } -void AArch64::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { +void AArch64::writeGotPlt(uint8_t *Buf, const Symbol &) const { write64le(Buf, InX::Plt->getVA()); } @@ -180,6 +190,31 @@ void AArch64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr); } +bool AArch64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const { + // ELF for the ARM 64-bit architecture, section Call and Jump relocations + // only permits range extension thunks for R_AARCH64_CALL26 and + // R_AARCH64_JUMP26 relocation types. + if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26) + return false; + uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); + return !inBranchRange(Type, BranchAddr, Dst); +} + +bool AArch64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { + if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26) + return true; + // The AArch64 call and unconditional branch instructions have a range of + // +/- 128 MiB. + uint64_t Range = 128 * 1024 * 1024; + if (Dst > Src) { + // Immediate of branch is signed. + Range -= 4; + return Dst - Src <= Range; + } + return Src - Dst <= Range; +} + static void write32AArch64Addr(uint8_t *L, uint64_t Imm) { uint32_t ImmLo = (Imm & 0x3) << 29; uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; @@ -201,7 +236,7 @@ static void or32AArch64Imm(uint8_t *L, uint64_t Imm) { or32le(L, (Imm & 0xFFF) << 10); } -void AArch64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_AARCH64_ABS16: case R_AARCH64_PREL16: @@ -232,12 +267,23 @@ void AArch64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { checkInt<21>(Loc, Val, Type); write32AArch64Addr(Loc, Val); break; - case R_AARCH64_CALL26: case R_AARCH64_JUMP26: + // Normally we would just write the bits of the immediate field, however + // when patching instructions for the cpu errata fix -fix-cortex-a53-843419 + // we want to replace a non-branch instruction with a branch immediate + // instruction. By writing all the bits of the instruction including the + // opcode and the immediate (0 001 | 01 imm26) we can do this + // transformation by placing a R_AARCH64_JUMP26 relocation at the offset of + // the instruction we want to patch. + write32le(Loc, 0x14000000); + LLVM_FALLTHROUGH; + case R_AARCH64_CALL26: checkInt<28>(Loc, Val, Type); or32le(Loc, (Val & 0x0FFFFFFC) >> 2); break; case R_AARCH64_CONDBR19: + case R_AARCH64_LD_PREL_LO19: + checkAlignment<4>(Loc, Val, Type); checkInt<21>(Loc, Val, Type); or32le(Loc, (Val & 0x1FFFFC) << 3); break; @@ -251,15 +297,19 @@ void AArch64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { or32AArch64Imm(Loc, getBits(Val, 0, 11)); break; case R_AARCH64_LDST16_ABS_LO12_NC: + checkAlignment<2>(Loc, Val, Type); or32AArch64Imm(Loc, getBits(Val, 1, 11)); break; case R_AARCH64_LDST32_ABS_LO12_NC: + checkAlignment<4>(Loc, Val, Type); or32AArch64Imm(Loc, getBits(Val, 2, 11)); break; case R_AARCH64_LDST64_ABS_LO12_NC: + checkAlignment<8>(Loc, Val, Type); or32AArch64Imm(Loc, getBits(Val, 3, 11)); break; case R_AARCH64_LDST128_ABS_LO12_NC: + checkAlignment<16>(Loc, Val, Type); or32AArch64Imm(Loc, getBits(Val, 4, 11)); break; case R_AARCH64_MOVW_UABS_G0_NC: @@ -291,7 +341,7 @@ void AArch64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { } } -void AArch64::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +void AArch64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // TLSDESC Global-Dynamic relocation are in the form: // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] @@ -321,7 +371,7 @@ void AArch64::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { } } -void AArch64::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +void AArch64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { // TLSDESC Global-Dynamic relocation are in the form: // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] @@ -352,7 +402,7 @@ void AArch64::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { } } -void AArch64::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +void AArch64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { checkUInt<32>(Loc, Val, Type); if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) { diff --git a/ELF/Arch/AMDGPU.cpp b/ELF/Arch/AMDGPU.cpp index de566c617ac0..505e0e6ad480 100644 --- a/ELF/Arch/AMDGPU.cpp +++ b/ELF/Arch/AMDGPU.cpp @@ -7,10 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" @@ -25,19 +25,38 @@ namespace { class AMDGPU final : public TargetInfo { public: AMDGPU(); - void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + uint32_t calcEFlags() const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; }; } // namespace AMDGPU::AMDGPU() { - RelativeRel = R_AMDGPU_REL64; + RelativeRel = R_AMDGPU_RELATIVE64; GotRel = R_AMDGPU_ABS64; GotEntrySize = 8; } -void AMDGPU::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +static uint32_t getEFlags(InputFile *File) { + return cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags; +} + +uint32_t AMDGPU::calcEFlags() const { + assert(!ObjectFiles.empty()); + uint32_t Ret = getEFlags(ObjectFiles[0]); + + // Verify that all input files have the same e_flags. + for (InputFile *F : makeArrayRef(ObjectFiles).slice(1)) { + if (Ret == getEFlags(F)) + continue; + error("incompatible e_flags: " + toString(F)); + return 0; + } + return Ret; +} + +void AMDGPU::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_AMDGPU_ABS32: case R_AMDGPU_GOTPCREL: @@ -58,7 +77,7 @@ void AMDGPU::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { } } -RelExpr AMDGPU::getRelExpr(uint32_t Type, const SymbolBody &S, +RelExpr AMDGPU::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { case R_AMDGPU_ABS32: @@ -73,8 +92,7 @@ RelExpr AMDGPU::getRelExpr(uint32_t Type, const SymbolBody &S, case R_AMDGPU_GOTPCREL32_HI: return R_GOT_PC; default: - error(toString(S.File) + ": unknown relocation type: " + toString(Type)); - return R_HINT; + return R_INVALID; } } diff --git a/ELF/Arch/ARM.cpp b/ELF/Arch/ARM.cpp index 106021de7d32..94a98e7679bd 100644 --- a/ELF/Arch/ARM.cpp +++ b/ELF/Arch/ARM.cpp @@ -7,12 +7,12 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" @@ -26,23 +26,23 @@ namespace { class ARM final : public TargetInfo { public: ARM(); - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + uint32_t calcEFlags() const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; - bool isPicRel(uint32_t Type) const override; - uint32_t getDynRel(uint32_t Type) const override; - int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; - void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; - void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override; + bool isPicRel(RelType Type) const override; + RelType getDynRel(RelType Type) const override; + int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void addPltSymbols(InputSectionBase *IS, uint64_t Off) const override; void addPltHeaderSymbols(InputSectionBase *ISD) const override; - bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, - const SymbolBody &S) const override; - bool inBranchRange(uint32_t RelocType, uint64_t Src, - uint64_t Dst) const override; - void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const override; + bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace @@ -58,18 +58,54 @@ ARM::ARM() { GotEntrySize = 4; GotPltEntrySize = 4; PltEntrySize = 16; - PltHeaderSize = 20; + PltHeaderSize = 32; TrapInstr = 0xd4d4d4d4; // ARM uses Variant 1 TLS TcbSize = 8; NeedsThunks = true; + + // The placing of pre-created ThunkSections is controlled by the + // ThunkSectionSpacing parameter. The aim is to place the + // ThunkSection such that all branches from the InputSections prior to the + // ThunkSection can reach a Thunk placed at the end of the ThunkSection. + // Graphically: + // | up to ThunkSectionSpacing .text input sections | + // | ThunkSection | + // | up to ThunkSectionSpacing .text input sections | + // | ThunkSection | + + // Pre-created ThunkSections are spaced roughly 16MiB apart on ARM. This is to + // match the most common expected case of a Thumb 2 encoded BL, BLX or B.W + // ARM B, BL, BLX range +/- 32MiB + // Thumb B.W, BL, BLX range +/- 16MiB + // Thumb B<cc>.W range +/- 1MiB + // If a branch cannot reach a pre-created ThunkSection a new one will be + // created so we can handle the rare cases of a Thumb 2 conditional branch. + // We intentionally use a lower size for ThunkSectionSpacing than the maximum + // branch range so the end of the ThunkSection is more likely to be within + // range of the branch instruction that is furthest away. The value we shorten + // ThunkSectionSpacing by is set conservatively to allow us to create 16,384 + // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to + // one of the Thunks going out of range. + + // FIXME: lld assumes that the Thumb BL and BLX encoding permits the J1 and + // J2 bits to be used to extend the branch range. On earlier Architectures + // such as ARMv4, ARMv5 and ARMv6 (except ARMv6T2) the range is +/- 4MiB. If + // support for the earlier encodings is added then when they are used the + // ThunkSectionSpacing will need lowering. + ThunkSectionSpacing = 0x1000000 - 0x30000; +} + +uint32_t ARM::calcEFlags() const { + // We don't currently use any features incompatible with EF_ARM_EABI_VER5, + // but we don't have any firm guarantees of conformance. Linux AArch64 + // kernels (as of 2016) require an EABI version to be set. + return EF_ARM_EABI_VER5; } -RelExpr ARM::getRelExpr(uint32_t Type, const SymbolBody &S, +RelExpr ARM::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { - default: - return R_ABS; case R_ARM_THM_JUMP11: return R_PC; case R_ARM_CALL: @@ -120,15 +156,17 @@ RelExpr ARM::getRelExpr(uint32_t Type, const SymbolBody &S, return R_NONE; case R_ARM_TLS_LE32: return R_TLS; + default: + return R_ABS; } } -bool ARM::isPicRel(uint32_t Type) const { +bool ARM::isPicRel(RelType Type) const { return (Type == R_ARM_TARGET1 && !Config->Target1Rel) || (Type == R_ARM_ABS32); } -uint32_t ARM::getDynRel(uint32_t Type) const { +RelType ARM::getDynRel(RelType Type) const { if (Type == R_ARM_TARGET1 && !Config->Target1Rel) return R_ARM_ABS32; if (Type == R_ARM_ABS32) @@ -137,41 +175,74 @@ uint32_t ARM::getDynRel(uint32_t Type) const { return R_ARM_ABS32; } -void ARM::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { +void ARM::writeGotPlt(uint8_t *Buf, const Symbol &) const { write32le(Buf, InX::Plt->getVA()); } -void ARM::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const { +void ARM::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { // An ARM entry is the address of the ifunc resolver function. write32le(Buf, S.getVA()); } -void ARM::writePltHeader(uint8_t *Buf) const { +// Long form PLT Heade that does not have any restrictions on the displacement +// of the .plt from the .plt.got. +static void writePltHeaderLong(uint8_t *Buf) { const uint8_t PltData[] = { 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]! 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr 0x08, 0xf0, 0xbe, 0xe5, // ldr pc, [lr, #8] 0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8 - }; + 0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary + 0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary + 0xd4, 0xd4, 0xd4, 0xd4}; memcpy(Buf, PltData, sizeof(PltData)); uint64_t GotPlt = InX::GotPlt->getVA(); uint64_t L1 = InX::Plt->getVA() + 8; write32le(Buf + 16, GotPlt - L1 - 8); } +// The default PLT header requires the .plt.got to be within 128 Mb of the +// .plt in the positive direction. +void ARM::writePltHeader(uint8_t *Buf) const { + // Use a similar sequence to that in writePlt(), the difference is the calling + // conventions mean we use lr instead of ip. The PLT entry is responsible for + // saving lr on the stack, the dynamic loader is responsible for reloading + // it. + const uint32_t PltData[] = { + 0xe52de004, // L1: str lr, [sp,#-4]! + 0xe28fe600, // add lr, pc, #0x0NN00000 &(.got.plt - L1 - 4) + 0xe28eea00, // add lr, lr, #0x000NN000 &(.got.plt - L1 - 4) + 0xe5bef000, // ldr pc, [lr, #0x00000NNN] &(.got.plt -L1 - 4) + }; + + uint64_t Offset = InX::GotPlt->getVA() - InX::Plt->getVA() - 4; + if (!llvm::isUInt<27>(Offset)) { + // We cannot encode the Offset, use the long form. + writePltHeaderLong(Buf); + return; + } + write32le(Buf + 0, PltData[0]); + write32le(Buf + 4, PltData[1] | ((Offset >> 20) & 0xff)); + write32le(Buf + 8, PltData[2] | ((Offset >> 12) & 0xff)); + write32le(Buf + 12, PltData[3] | (Offset & 0xfff)); + write32le(Buf + 16, TrapInstr); // Pad to 32-byte boundary + write32le(Buf + 20, TrapInstr); + write32le(Buf + 24, TrapInstr); + write32le(Buf + 28, TrapInstr); +} + void ARM::addPltHeaderSymbols(InputSectionBase *ISD) const { auto *IS = cast<InputSection>(ISD); addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS); } -void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, - uint64_t PltEntryAddr, int32_t Index, - unsigned RelOff) const { - // FIXME: Using simple code sequence with simple relocations. - // There is a more optimal sequence but it requires support for the group - // relocations. See ELF for the ARM Architecture Appendix A.3 +// Long form PLT entries that do not have any restrictions on the displacement +// of the .plt from the .plt.got. +static void writePltLong(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) { const uint8_t PltData[] = { 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc @@ -183,24 +254,50 @@ void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, write32le(Buf + 12, GotPltEntryAddr - L1 - 8); } +// The default PLT entries require the .plt.got to be within 128 Mb of the +// .plt in the positive direction. +void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + // The PLT entry is similar to the example given in Appendix A of ELF for + // the Arm Architecture. Instead of using the Group Relocations to find the + // optimal rotation for the 8-bit immediate used in the add instructions we + // hard code the most compact rotations for simplicity. This saves a load + // instruction over the long plt sequences. + const uint32_t PltData[] = { + 0xe28fc600, // L1: add ip, pc, #0x0NN00000 Offset(&(.plt.got) - L1 - 8 + 0xe28cca00, // add ip, ip, #0x000NN000 Offset(&(.plt.got) - L1 - 8 + 0xe5bcf000, // ldr pc, [ip, #0x00000NNN] Offset(&(.plt.got) - L1 - 8 + }; + + uint64_t Offset = GotPltEntryAddr - PltEntryAddr - 8; + if (!llvm::isUInt<27>(Offset)) { + // We cannot encode the Offset, use the long form. + writePltLong(Buf, GotPltEntryAddr, PltEntryAddr, Index, RelOff); + return; + } + write32le(Buf + 0, PltData[0] | ((Offset >> 20) & 0xff)); + write32le(Buf + 4, PltData[1] | ((Offset >> 12) & 0xff)); + write32le(Buf + 8, PltData[2] | (Offset & 0xfff)); + write32le(Buf + 12, TrapInstr); // Pad to 16-byte boundary +} + void ARM::addPltSymbols(InputSectionBase *ISD, uint64_t Off) const { auto *IS = cast<InputSection>(ISD); addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS); } -bool ARM::needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, - const SymbolBody &S) const { - // If S is an undefined weak symbol in an executable we don't need a Thunk. - // In a DSO calls to undefined symbols, including weak ones get PLT entries - // which may need a thunk. - if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak() && - !Config->Shared) +bool ARM::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const { + // If S is an undefined weak symbol and does not have a PLT entry then it + // will be resolved as a branch to the next instruction. + if (S.isUndefWeak() && !S.isInPlt()) return false; // A state change from ARM to Thumb and vice versa must go through an // interworking thunk if the relocation type is not R_ARM_CALL or // R_ARM_THM_CALL. - switch (RelocType) { + switch (Type) { case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_JUMP24: @@ -208,23 +305,31 @@ bool ARM::needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, // Otherwise we need to interwork if Symbol has bit 0 set (Thumb). if (Expr == R_PC && ((S.getVA() & 1) == 1)) return true; - break; + LLVM_FALLTHROUGH; + case R_ARM_CALL: { + uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); + return !inBranchRange(Type, BranchAddr, Dst); + } case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: // Source is Thumb, all PLT entries are ARM so interworking is required. // Otherwise we need to interwork if Symbol has bit 0 clear (ARM). if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0)) return true; - break; + LLVM_FALLTHROUGH; + case R_ARM_THM_CALL: { + uint64_t Dst = (Expr == R_PLT_PC) ? S.getPltVA() : S.getVA(); + return !inBranchRange(Type, BranchAddr, Dst); + } } return false; } -bool ARM::inBranchRange(uint32_t RelocType, uint64_t Src, uint64_t Dst) const { +bool ARM::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { uint64_t Range; uint64_t InstrSize; - switch (RelocType) { + switch (Type) { case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_JUMP24: @@ -263,7 +368,7 @@ bool ARM::inBranchRange(uint32_t RelocType, uint64_t Src, uint64_t Dst) const { return Distance <= Range; } -void ARM::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_ARM_ABS32: case R_ARM_BASE_PREL: @@ -400,7 +505,7 @@ void ARM::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { } } -int64_t ARM::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { +int64_t ARM::getImplicitAddend(const uint8_t *Buf, RelType Type) const { switch (Type) { default: return 0; diff --git a/ELF/Arch/AVR.cpp b/ELF/Arch/AVR.cpp index 3853248f8fbd..02ac770127b9 100644 --- a/ELF/Arch/AVR.cpp +++ b/ELF/Arch/AVR.cpp @@ -26,10 +26,10 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" @@ -43,24 +43,18 @@ using namespace lld::elf; namespace { class AVR final : public TargetInfo { public: - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; - void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace -RelExpr AVR::getRelExpr(uint32_t Type, const SymbolBody &S, +RelExpr AVR::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { - switch (Type) { - case R_AVR_CALL: - return R_ABS; - default: - error(toString(S.File) + ": unknown relocation type: " + toString(Type)); - return R_HINT; - } + return R_ABS; } -void AVR::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +void AVR::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_AVR_CALL: { uint16_t Hi = Val >> 17; diff --git a/ELF/Arch/Mips.cpp b/ELF/Arch/Mips.cpp index b8d796f5897a..495e2567006f 100644 --- a/ELF/Arch/Mips.cpp +++ b/ELF/Arch/Mips.cpp @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "OutputSections.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" @@ -28,19 +28,20 @@ namespace { template <class ELFT> class MIPS final : public TargetInfo { public: MIPS(); - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + uint32_t calcEFlags() const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; - int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; - bool isPicRel(uint32_t Type) const override; - uint32_t getDynRel(uint32_t Type) const override; - void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; + int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; + bool isPicRel(RelType Type) const override; + RelType getDynRel(RelType Type) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; - bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, - const SymbolBody &S) const override; - void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; - bool usesOnlyLowPageBits(uint32_t Type) const override; + bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + bool usesOnlyLowPageBits(RelType Type) const override; }; } // namespace @@ -69,24 +70,39 @@ template <class ELFT> MIPS<ELFT>::MIPS() { } } +template <class ELFT> uint32_t MIPS<ELFT>::calcEFlags() const { + return calcMipsEFlags<ELFT>(); +} + template <class ELFT> -RelExpr MIPS<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S, +RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { // See comment in the calculateMipsRelChain. if (ELFT::Is64Bits || Config->MipsN32Abi) Type &= 0xff; + switch (Type) { - default: - return R_ABS; case R_MIPS_JALR: + case R_MICROMIPS_JALR: return R_HINT; case R_MIPS_GPREL16: case R_MIPS_GPREL32: + case R_MICROMIPS_GPREL16: + case R_MICROMIPS_GPREL7_S2: return R_MIPS_GOTREL; case R_MIPS_26: + case R_MICROMIPS_26_S1: return R_PLT; + case R_MICROMIPS_PC26_S1: + return R_PLT_PC; case R_MIPS_HI16: case R_MIPS_LO16: + case R_MIPS_HIGHER: + case R_MIPS_HIGHEST: + case R_MICROMIPS_HI16: + case R_MICROMIPS_LO16: + case R_MICROMIPS_HIGHER: + case R_MICROMIPS_HIGHEST: // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate // offset between start of function and 'gp' value which by default // equal to the start of .got section. In that case we consider these @@ -96,7 +112,24 @@ RelExpr MIPS<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S, if (&S == ElfSym::MipsLocalGp) return R_MIPS_GOT_GP; LLVM_FALLTHROUGH; + case R_MIPS_32: + case R_MIPS_64: case R_MIPS_GOT_OFST: + case R_MIPS_SUB: + case R_MIPS_TLS_DTPREL_HI16: + case R_MIPS_TLS_DTPREL_LO16: + case R_MIPS_TLS_DTPREL32: + case R_MIPS_TLS_DTPREL64: + case R_MIPS_TLS_TPREL_HI16: + case R_MIPS_TLS_TPREL_LO16: + case R_MIPS_TLS_TPREL32: + case R_MIPS_TLS_TPREL64: + case R_MICROMIPS_GOT_OFST: + case R_MICROMIPS_SUB: + case R_MICROMIPS_TLS_DTPREL_HI16: + case R_MICROMIPS_TLS_DTPREL_LO16: + case R_MICROMIPS_TLS_TPREL_HI16: + case R_MICROMIPS_TLS_TPREL_LO16: return R_ABS; case R_MIPS_PC32: case R_MIPS_PC16: @@ -105,111 +138,171 @@ RelExpr MIPS<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S, case R_MIPS_PC26_S2: case R_MIPS_PCHI16: case R_MIPS_PCLO16: + case R_MICROMIPS_PC7_S1: + case R_MICROMIPS_PC10_S1: + case R_MICROMIPS_PC16_S1: + case R_MICROMIPS_PC18_S3: + case R_MICROMIPS_PC19_S2: + case R_MICROMIPS_PC23_S2: + case R_MICROMIPS_PC21_S1: return R_PC; case R_MIPS_GOT16: + case R_MICROMIPS_GOT16: if (S.isLocal()) return R_MIPS_GOT_LOCAL_PAGE; LLVM_FALLTHROUGH; case R_MIPS_CALL16: case R_MIPS_GOT_DISP: case R_MIPS_TLS_GOTTPREL: + case R_MICROMIPS_CALL16: + case R_MICROMIPS_GOT_DISP: + case R_MICROMIPS_TLS_GOTTPREL: return R_MIPS_GOT_OFF; case R_MIPS_CALL_HI16: case R_MIPS_CALL_LO16: case R_MIPS_GOT_HI16: case R_MIPS_GOT_LO16: + case R_MICROMIPS_CALL_HI16: + case R_MICROMIPS_CALL_LO16: + case R_MICROMIPS_GOT_HI16: + case R_MICROMIPS_GOT_LO16: return R_MIPS_GOT_OFF32; case R_MIPS_GOT_PAGE: + case R_MICROMIPS_GOT_PAGE: return R_MIPS_GOT_LOCAL_PAGE; case R_MIPS_TLS_GD: + case R_MICROMIPS_TLS_GD: return R_MIPS_TLSGD; case R_MIPS_TLS_LDM: + case R_MICROMIPS_TLS_LDM: return R_MIPS_TLSLD; + case R_MIPS_NONE: + return R_NONE; + default: + return R_INVALID; } } -template <class ELFT> bool MIPS<ELFT>::isPicRel(uint32_t Type) const { +template <class ELFT> bool MIPS<ELFT>::isPicRel(RelType Type) const { return Type == R_MIPS_32 || Type == R_MIPS_64; } -template <class ELFT> uint32_t MIPS<ELFT>::getDynRel(uint32_t Type) const { +template <class ELFT> RelType MIPS<ELFT>::getDynRel(RelType Type) const { return RelativeRel; } template <class ELFT> -void MIPS<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { - write32<ELFT::TargetEndianness>(Buf, InX::Plt->getVA()); -} - -template <endianness E, uint8_t BSIZE, uint8_t SHIFT> -static int64_t getPcRelocAddend(const uint8_t *Loc) { - uint32_t Instr = read32<E>(Loc); - uint32_t Mask = 0xffffffff >> (32 - BSIZE); - return SignExtend64<BSIZE + SHIFT>((Instr & Mask) << SHIFT); +void MIPS<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &) const { + uint64_t VA = InX::Plt->getVA(); + if (isMicroMips()) + VA |= 1; + write32<ELFT::TargetEndianness>(Buf, VA); } -template <endianness E, uint8_t BSIZE, uint8_t SHIFT> -static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t V) { - uint32_t Mask = 0xffffffff >> (32 - BSIZE); - uint32_t Instr = read32<E>(Loc); - if (SHIFT > 0) - checkAlignment<(1 << SHIFT)>(Loc, V, Type); - checkInt<BSIZE + SHIFT>(Loc, V, Type); - write32<E>(Loc, (Instr & ~Mask) | ((V >> SHIFT) & Mask)); +template <endianness E> static uint32_t readShuffle(const uint8_t *Loc) { + // The major opcode of a microMIPS instruction needs to appear + // in the first 16-bit word (lowest address) for efficient hardware + // decode so that it knows if the instruction is 16-bit or 32-bit + // as early as possible. To do so, little-endian binaries keep 16-bit + // words in a big-endian order. That is why we have to swap these + // words to get a correct value. + uint32_t V = read32<E>(Loc); + if (E == support::little) + return (V << 16) | (V >> 16); + return V; } -template <endianness E> static void writeMipsHi16(uint8_t *Loc, uint64_t V) { +template <endianness E> +static void writeRelocation(uint8_t *Loc, uint64_t V, uint8_t BitsSize, + uint8_t Shift) { uint32_t Instr = read32<E>(Loc); - uint16_t Res = ((V + 0x8000) >> 16) & 0xffff; - write32<E>(Loc, (Instr & 0xffff0000) | Res); + uint32_t Mask = 0xffffffff >> (32 - BitsSize); + uint32_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask); + write32<E>(Loc, Data); } -template <endianness E> static void writeMipsHigher(uint8_t *Loc, uint64_t V) { - uint32_t Instr = read32<E>(Loc); - uint16_t Res = ((V + 0x80008000) >> 32) & 0xffff; - write32<E>(Loc, (Instr & 0xffff0000) | Res); -} +template <endianness E> +static void writeMicroRelocation32(uint8_t *Loc, uint64_t V, uint8_t BitsSize, + uint8_t Shift) { + // See comments in readShuffle for purpose of this code. + uint16_t *Words = (uint16_t *)Loc; + if (E == support::little) + std::swap(Words[0], Words[1]); -template <endianness E> static void writeMipsHighest(uint8_t *Loc, uint64_t V) { - uint32_t Instr = read32<E>(Loc); - uint16_t Res = ((V + 0x800080008000) >> 48) & 0xffff; - write32<E>(Loc, (Instr & 0xffff0000) | Res); -} + writeRelocation<E>(Loc, V, BitsSize, Shift); -template <endianness E> static void writeMipsLo16(uint8_t *Loc, uint64_t V) { - uint32_t Instr = read32<E>(Loc); - write32<E>(Loc, (Instr & 0xffff0000) | (V & 0xffff)); + if (E == support::little) + std::swap(Words[0], Words[1]); } -template <class ELFT> static bool isMipsR6() { - const auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf); - uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH; - return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6; +template <endianness E> +static void writeMicroRelocation16(uint8_t *Loc, uint64_t V, uint8_t BitsSize, + uint8_t Shift) { + uint16_t Instr = read16<E>(Loc); + uint16_t Mask = 0xffff >> (16 - BitsSize); + uint16_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask); + write16<E>(Loc, Data); } template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const { const endianness E = ELFT::TargetEndianness; + if (isMicroMips()) { + uint64_t GotPlt = InX::GotPlt->getVA(); + uint64_t Plt = InX::Plt->getVA(); + // Overwrite trap instructions written by Writer::writeTrapInstr. + memset(Buf, 0, PltHeaderSize); + + write16<E>(Buf, isMipsR6() ? 0x7860 : 0x7980); // addiupc v1, (GOTPLT) - . + write16<E>(Buf + 4, 0xff23); // lw $25, 0($3) + write16<E>(Buf + 8, 0x0535); // subu16 $2, $2, $3 + write16<E>(Buf + 10, 0x2525); // srl16 $2, $2, 2 + write16<E>(Buf + 12, 0x3302); // addiu $24, $2, -2 + write16<E>(Buf + 14, 0xfffe); + write16<E>(Buf + 16, 0x0dff); // move $15, $31 + if (isMipsR6()) { + write16<E>(Buf + 18, 0x0f83); // move $28, $3 + write16<E>(Buf + 20, 0x472b); // jalrc $25 + write16<E>(Buf + 22, 0x0c00); // nop + relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPlt - Plt); + } else { + write16<E>(Buf + 18, 0x45f9); // jalrc $25 + write16<E>(Buf + 20, 0x0f83); // move $28, $3 + write16<E>(Buf + 22, 0x0c00); // nop + relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPlt - Plt); + } + return; + } + if (Config->MipsN32Abi) { write32<E>(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) write32<E>(Buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14) write32<E>(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) write32<E>(Buf + 12, 0x030ec023); // subu $24, $24, $14 + write32<E>(Buf + 16, 0x03e07825); // move $15, $31 + write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2 + } else if (ELFT::Is64Bits) { + write32<E>(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) + write32<E>(Buf + 4, 0xddd90000); // ld $25, %lo(&GOTPLT[0])($14) + write32<E>(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) + write32<E>(Buf + 12, 0x030ec023); // subu $24, $24, $14 + write32<E>(Buf + 16, 0x03e07825); // move $15, $31 + write32<E>(Buf + 20, 0x0018c0c2); // srl $24, $24, 3 } else { write32<E>(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0]) write32<E>(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28) write32<E>(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0]) write32<E>(Buf + 12, 0x031cc023); // subu $24, $24, $28 + write32<E>(Buf + 16, 0x03e07825); // move $15, $31 + write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2 } - write32<E>(Buf + 16, 0x03e07825); // move $15, $31 - write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2 write32<E>(Buf + 24, 0x0320f809); // jalr $25 write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2 uint64_t GotPlt = InX::GotPlt->getVA(); - writeMipsHi16<E>(Buf, GotPlt); - writeMipsLo16<E>(Buf + 4, GotPlt); - writeMipsLo16<E>(Buf + 8, GotPlt); + writeRelocation<E>(Buf, GotPlt + 0x8000, 16, 16); + writeRelocation<E>(Buf + 4, GotPlt, 16, 0); + writeRelocation<E>(Buf + 8, GotPlt, 16, 0); } template <class ELFT> @@ -217,25 +310,45 @@ void MIPS<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const endianness E = ELFT::TargetEndianness; + if (isMicroMips()) { + // Overwrite trap instructions written by Writer::writeTrapInstr. + memset(Buf, 0, PltEntrySize); + + if (isMipsR6()) { + write16<E>(Buf, 0x7840); // addiupc $2, (GOTPLT) - . + write16<E>(Buf + 4, 0xff22); // lw $25, 0($2) + write16<E>(Buf + 8, 0x0f02); // move $24, $2 + write16<E>(Buf + 10, 0x4723); // jrc $25 / jr16 $25 + relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPltEntryAddr - PltEntryAddr); + } else { + write16<E>(Buf, 0x7900); // addiupc $2, (GOTPLT) - . + write16<E>(Buf + 4, 0xff22); // lw $25, 0($2) + write16<E>(Buf + 8, 0x4599); // jrc $25 / jr16 $25 + write16<E>(Buf + 10, 0x0f02); // move $24, $2 + relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPltEntryAddr - PltEntryAddr); + } + return; + } + write32<E>(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry) write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15) - // jr $25 - write32<E>(Buf + 8, isMipsR6<ELFT>() ? 0x03200009 : 0x03200008); + write32<E>(Buf + 8, isMipsR6() ? 0x03200009 : 0x03200008); // jr $25 write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry) - writeMipsHi16<E>(Buf, GotPltEntryAddr); - writeMipsLo16<E>(Buf + 4, GotPltEntryAddr); - writeMipsLo16<E>(Buf + 12, GotPltEntryAddr); + writeRelocation<E>(Buf, GotPltEntryAddr + 0x8000, 16, 16); + writeRelocation<E>(Buf + 4, GotPltEntryAddr, 16, 0); + writeRelocation<E>(Buf + 12, GotPltEntryAddr, 16, 0); } template <class ELFT> -bool MIPS<ELFT>::needsThunk(RelExpr Expr, uint32_t Type, const InputFile *File, - const SymbolBody &S) const { +bool MIPS<ELFT>::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const { // Any MIPS PIC code function is invoked with its address in register $t9. // So if we have a branch instruction from non-PIC code to the PIC one // we cannot make the jump directly and need to create a small stubs // to save the target function address. // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - if (Type != R_MIPS_26) + if (Type != R_MIPS_26 && Type != R_MICROMIPS_26_S1 && + Type != R_MICROMIPS_PC26_S1) return false; auto *F = dyn_cast_or_null<ELFFileBase<ELFT>>(File); if (!F) @@ -243,18 +356,16 @@ bool MIPS<ELFT>::needsThunk(RelExpr Expr, uint32_t Type, const InputFile *File, // If current file has PIC code, LA25 stub is not required. if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC) return false; - auto *D = dyn_cast<DefinedRegular>(&S); + auto *D = dyn_cast<Defined>(&S); // LA25 is required if target file has PIC code // or target symbol is a PIC symbol. - return D && D->isMipsPIC<ELFT>(); + return D && isMipsPIC<ELFT>(D); } template <class ELFT> -int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { +int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *Buf, RelType Type) const { const endianness E = ELFT::TargetEndianness; switch (Type) { - default: - return 0; case R_MIPS_32: case R_MIPS_GPREL32: case R_MIPS_TLS_DTPREL32: @@ -264,7 +375,11 @@ int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { // FIXME (simon): If the relocation target symbol is not a PLT entry // we should use another expression for calculation: // ((A << 2) | (P & 0xf0000000)) >> 2 - return SignExtend64<28>((read32<E>(Buf) & 0x3ffffff) << 2); + return SignExtend64<28>(read32<E>(Buf) << 2); + case R_MIPS_GOT16: + case R_MIPS_HI16: + case R_MIPS_PCHI16: + return SignExtend64<16>(read32<E>(Buf)) << 16; case R_MIPS_GPREL16: case R_MIPS_LO16: case R_MIPS_PCLO16: @@ -273,21 +388,53 @@ int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { case R_MIPS_TLS_TPREL_HI16: case R_MIPS_TLS_TPREL_LO16: return SignExtend64<16>(read32<E>(Buf)); + case R_MICROMIPS_GOT16: + case R_MICROMIPS_HI16: + return SignExtend64<16>(readShuffle<E>(Buf)) << 16; + case R_MICROMIPS_GPREL16: + case R_MICROMIPS_LO16: + case R_MICROMIPS_TLS_DTPREL_HI16: + case R_MICROMIPS_TLS_DTPREL_LO16: + case R_MICROMIPS_TLS_TPREL_HI16: + case R_MICROMIPS_TLS_TPREL_LO16: + return SignExtend64<16>(readShuffle<E>(Buf)); + case R_MICROMIPS_GPREL7_S2: + return SignExtend64<9>(readShuffle<E>(Buf) << 2); case R_MIPS_PC16: - return getPcRelocAddend<E, 16, 2>(Buf); + return SignExtend64<18>(read32<E>(Buf) << 2); case R_MIPS_PC19_S2: - return getPcRelocAddend<E, 19, 2>(Buf); + return SignExtend64<21>(read32<E>(Buf) << 2); case R_MIPS_PC21_S2: - return getPcRelocAddend<E, 21, 2>(Buf); + return SignExtend64<23>(read32<E>(Buf) << 2); case R_MIPS_PC26_S2: - return getPcRelocAddend<E, 26, 2>(Buf); + return SignExtend64<28>(read32<E>(Buf) << 2); case R_MIPS_PC32: - return getPcRelocAddend<E, 32, 0>(Buf); + return SignExtend64<32>(read32<E>(Buf)); + case R_MICROMIPS_26_S1: + return SignExtend64<27>(readShuffle<E>(Buf) << 1); + case R_MICROMIPS_PC7_S1: + return SignExtend64<8>(read16<E>(Buf) << 1); + case R_MICROMIPS_PC10_S1: + return SignExtend64<11>(read16<E>(Buf) << 1); + case R_MICROMIPS_PC16_S1: + return SignExtend64<17>(readShuffle<E>(Buf) << 1); + case R_MICROMIPS_PC18_S3: + return SignExtend64<21>(readShuffle<E>(Buf) << 3); + case R_MICROMIPS_PC19_S2: + return SignExtend64<21>(readShuffle<E>(Buf) << 2); + case R_MICROMIPS_PC21_S1: + return SignExtend64<22>(readShuffle<E>(Buf) << 1); + case R_MICROMIPS_PC23_S2: + return SignExtend64<25>(readShuffle<E>(Buf) << 2); + case R_MICROMIPS_PC26_S1: + return SignExtend64<27>(readShuffle<E>(Buf) << 1); + default: + return 0; } } static std::pair<uint32_t, uint64_t> -calculateMipsRelChain(uint8_t *Loc, uint32_t Type, uint64_t Val) { +calculateMipsRelChain(uint8_t *Loc, RelType Type, uint64_t Val) { // MIPS N64 ABI packs multiple relocations into the single relocation // record. In general, all up to three relocations can have arbitrary // types. In fact, Clang and GCC uses only a few combinations. For now, @@ -300,32 +447,43 @@ calculateMipsRelChain(uint8_t *Loc, uint32_t Type, uint64_t Val) { // relocations used to modify result of the first one: extend it to // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf - uint32_t Type2 = (Type >> 8) & 0xff; - uint32_t Type3 = (Type >> 16) & 0xff; + RelType Type2 = (Type >> 8) & 0xff; + RelType Type3 = (Type >> 16) & 0xff; if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE) return std::make_pair(Type, Val); if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE) return std::make_pair(Type2, Val); if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16)) return std::make_pair(Type3, -Val); + if (Type2 == R_MICROMIPS_SUB && + (Type3 == R_MICROMIPS_HI16 || Type3 == R_MICROMIPS_LO16)) + return std::make_pair(Type3, -Val); error(getErrorLocation(Loc) + "unsupported relocations combination " + Twine(Type)); return std::make_pair(Type & 0xff, Val); } template <class ELFT> -void MIPS<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { const endianness E = ELFT::TargetEndianness; + // Thread pointer and DRP offsets from the start of TLS data area. // https://www.linux-mips.org/wiki/NPTL if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 || - Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64) + Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64 || + Type == R_MICROMIPS_TLS_DTPREL_HI16 || + Type == R_MICROMIPS_TLS_DTPREL_LO16) { Val -= 0x8000; - else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 || - Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64) + } else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 || + Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64 || + Type == R_MICROMIPS_TLS_TPREL_HI16 || + Type == R_MICROMIPS_TLS_TPREL_LO16) { Val -= 0x7000; + } + if (ELFT::Is64Bits || Config->MipsN32Abi) std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val); + switch (Type) { case R_MIPS_32: case R_MIPS_GPREL32: @@ -339,36 +497,65 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { write64<E>(Loc, Val); break; case R_MIPS_26: - write32<E>(Loc, (read32<E>(Loc) & ~0x3ffffff) | ((Val >> 2) & 0x3ffffff)); + writeRelocation<E>(Loc, Val, 26, 2); break; case R_MIPS_GOT16: // The R_MIPS_GOT16 relocation's value in "relocatable" linking mode // is updated addend (not a GOT index). In that case write high 16 bits // to store a correct addend value. - if (Config->Relocatable) - writeMipsHi16<E>(Loc, Val); - else { + if (Config->Relocatable) { + writeRelocation<E>(Loc, Val + 0x8000, 16, 16); + } else { checkInt<16>(Loc, Val, Type); - writeMipsLo16<E>(Loc, Val); + writeRelocation<E>(Loc, Val, 16, 0); } break; + case R_MICROMIPS_GOT16: + if (Config->Relocatable) { + writeMicroRelocation32<E>(Loc, Val + 0x8000, 16, 16); + } else { + checkInt<16>(Loc, Val, Type); + writeMicroRelocation32<E>(Loc, Val, 16, 0); + } + break; + case R_MIPS_CALL16: case R_MIPS_GOT_DISP: case R_MIPS_GOT_PAGE: case R_MIPS_GPREL16: case R_MIPS_TLS_GD: + case R_MIPS_TLS_GOTTPREL: case R_MIPS_TLS_LDM: checkInt<16>(Loc, Val, Type); LLVM_FALLTHROUGH; - case R_MIPS_CALL16: case R_MIPS_CALL_LO16: case R_MIPS_GOT_LO16: case R_MIPS_GOT_OFST: case R_MIPS_LO16: case R_MIPS_PCLO16: case R_MIPS_TLS_DTPREL_LO16: - case R_MIPS_TLS_GOTTPREL: case R_MIPS_TLS_TPREL_LO16: - writeMipsLo16<E>(Loc, Val); + writeRelocation<E>(Loc, Val, 16, 0); + break; + case R_MICROMIPS_GOT_DISP: + case R_MICROMIPS_GOT_PAGE: + case R_MICROMIPS_GPREL16: + case R_MICROMIPS_TLS_GD: + case R_MICROMIPS_TLS_LDM: + checkInt<16>(Loc, Val, Type); + writeMicroRelocation32<E>(Loc, Val, 16, 0); + break; + case R_MICROMIPS_CALL16: + case R_MICROMIPS_CALL_LO16: + case R_MICROMIPS_GOT_OFST: + case R_MICROMIPS_LO16: + case R_MICROMIPS_TLS_DTPREL_LO16: + case R_MICROMIPS_TLS_GOTTPREL: + case R_MICROMIPS_TLS_TPREL_LO16: + writeMicroRelocation32<E>(Loc, Val, 16, 0); + break; + case R_MICROMIPS_GPREL7_S2: + checkInt<7>(Loc, Val, Type); + writeMicroRelocation32<E>(Loc, Val, 7, 2); break; case R_MIPS_CALL_HI16: case R_MIPS_GOT_HI16: @@ -376,40 +563,107 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { case R_MIPS_PCHI16: case R_MIPS_TLS_DTPREL_HI16: case R_MIPS_TLS_TPREL_HI16: - writeMipsHi16<E>(Loc, Val); + writeRelocation<E>(Loc, Val + 0x8000, 16, 16); + break; + case R_MICROMIPS_CALL_HI16: + case R_MICROMIPS_GOT_HI16: + case R_MICROMIPS_HI16: + case R_MICROMIPS_TLS_DTPREL_HI16: + case R_MICROMIPS_TLS_TPREL_HI16: + writeMicroRelocation32<E>(Loc, Val + 0x8000, 16, 16); break; case R_MIPS_HIGHER: - writeMipsHigher<E>(Loc, Val); + writeRelocation<E>(Loc, Val + 0x80008000, 16, 32); break; case R_MIPS_HIGHEST: - writeMipsHighest<E>(Loc, Val); + writeRelocation<E>(Loc, Val + 0x800080008000, 16, 48); + break; + case R_MICROMIPS_HIGHER: + writeMicroRelocation32<E>(Loc, Val + 0x80008000, 16, 32); + break; + case R_MICROMIPS_HIGHEST: + writeMicroRelocation32<E>(Loc, Val + 0x800080008000, 16, 48); break; case R_MIPS_JALR: + case R_MICROMIPS_JALR: // Ignore this optimization relocation for now break; case R_MIPS_PC16: - applyMipsPcReloc<E, 16, 2>(Loc, Type, Val); + checkAlignment<4>(Loc, Val, Type); + checkInt<18>(Loc, Val, Type); + writeRelocation<E>(Loc, Val, 16, 2); break; case R_MIPS_PC19_S2: - applyMipsPcReloc<E, 19, 2>(Loc, Type, Val); + checkAlignment<4>(Loc, Val, Type); + checkInt<21>(Loc, Val, Type); + writeRelocation<E>(Loc, Val, 19, 2); break; case R_MIPS_PC21_S2: - applyMipsPcReloc<E, 21, 2>(Loc, Type, Val); + checkAlignment<4>(Loc, Val, Type); + checkInt<23>(Loc, Val, Type); + writeRelocation<E>(Loc, Val, 21, 2); break; case R_MIPS_PC26_S2: - applyMipsPcReloc<E, 26, 2>(Loc, Type, Val); + checkAlignment<4>(Loc, Val, Type); + checkInt<28>(Loc, Val, Type); + writeRelocation<E>(Loc, Val, 26, 2); break; case R_MIPS_PC32: - applyMipsPcReloc<E, 32, 0>(Loc, Type, Val); + writeRelocation<E>(Loc, Val, 32, 0); + break; + case R_MICROMIPS_26_S1: + case R_MICROMIPS_PC26_S1: + checkInt<27>(Loc, Val, Type); + writeMicroRelocation32<E>(Loc, Val, 26, 1); + break; + case R_MICROMIPS_PC7_S1: + checkInt<8>(Loc, Val, Type); + writeMicroRelocation16<E>(Loc, Val, 7, 1); + break; + case R_MICROMIPS_PC10_S1: + checkInt<11>(Loc, Val, Type); + writeMicroRelocation16<E>(Loc, Val, 10, 1); + break; + case R_MICROMIPS_PC16_S1: + checkInt<17>(Loc, Val, Type); + writeMicroRelocation32<E>(Loc, Val, 16, 1); + break; + case R_MICROMIPS_PC18_S3: + checkInt<21>(Loc, Val, Type); + writeMicroRelocation32<E>(Loc, Val, 18, 3); + break; + case R_MICROMIPS_PC19_S2: + checkInt<21>(Loc, Val, Type); + writeMicroRelocation32<E>(Loc, Val, 19, 2); + break; + case R_MICROMIPS_PC21_S1: + checkInt<22>(Loc, Val, Type); + writeMicroRelocation32<E>(Loc, Val, 21, 1); + break; + case R_MICROMIPS_PC23_S2: + checkInt<25>(Loc, Val, Type); + writeMicroRelocation32<E>(Loc, Val, 23, 2); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } -template <class ELFT> -bool MIPS<ELFT>::usesOnlyLowPageBits(uint32_t Type) const { - return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST; +template <class ELFT> bool MIPS<ELFT>::usesOnlyLowPageBits(RelType Type) const { + return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST || + Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_GOT_OFST; +} + +// Return true if the symbol is a PIC function. +template <class ELFT> bool elf::isMipsPIC(const Defined *Sym) { + typedef typename ELFT::Ehdr Elf_Ehdr; + if (!Sym->Section || !Sym->isFunc()) + return false; + + auto *Sec = cast<InputSectionBase>(Sym->Section); + const Elf_Ehdr *Hdr = Sec->template getFile<ELFT>()->getObj().getHeader(); + return (Sym->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC || + (Hdr->e_flags & EF_MIPS_PIC); } template <class ELFT> TargetInfo *elf::getMipsTargetInfo() { @@ -421,3 +675,8 @@ template TargetInfo *elf::getMipsTargetInfo<ELF32LE>(); template TargetInfo *elf::getMipsTargetInfo<ELF32BE>(); template TargetInfo *elf::getMipsTargetInfo<ELF64LE>(); template TargetInfo *elf::getMipsTargetInfo<ELF64BE>(); + +template bool elf::isMipsPIC<ELF32LE>(const Defined *); +template bool elf::isMipsPIC<ELF32BE>(const Defined *); +template bool elf::isMipsPIC<ELF64LE>(const Defined *); +template bool elf::isMipsPIC<ELF64BE>(const Defined *); diff --git a/ELF/Arch/MipsArchTree.cpp b/ELF/Arch/MipsArchTree.cpp index 3d1dc1daf0c1..754a47001579 100644 --- a/ELF/Arch/MipsArchTree.cpp +++ b/ELF/Arch/MipsArchTree.cpp @@ -11,11 +11,11 @@ // //===---------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "SymbolTable.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" #include "llvm/Support/MipsABIFlags.h" @@ -34,7 +34,7 @@ struct ArchTreeEdge { }; struct FileFlags { - StringRef Filename; + InputFile *File; uint32_t Flags; }; } // namespace @@ -73,17 +73,17 @@ static void checkFlags(ArrayRef<FileFlags> Files) { uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); if (ABI != ABI2) error("target ABI '" + getAbiName(ABI) + "' is incompatible with '" + - getAbiName(ABI2) + "': " + F.Filename); + getAbiName(ABI2) + "': " + toString(F.File)); bool Nan2 = F.Flags & EF_MIPS_NAN2008; if (Nan != Nan2) error("target -mnan=" + getNanName(Nan) + " is incompatible with -mnan=" + - getNanName(Nan2) + ": " + F.Filename); + getNanName(Nan2) + ": " + toString(F.File)); bool Fp2 = F.Flags & EF_MIPS_FP64; if (Fp != Fp2) error("target -mfp" + getFpName(Fp) + " is incompatible with -mfp" + - getFpName(Fp2) + ": " + F.Filename); + getFpName(Fp2) + ": " + toString(F.File)); } } @@ -102,9 +102,11 @@ static uint32_t getPicFlags(ArrayRef<FileFlags> Files) { for (const FileFlags &F : Files.slice(1)) { bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); if (IsPic && !IsPic2) - warn("linking abicalls code with non-abicalls file: " + F.Filename); + warn("linking abicalls code " + toString(Files[0].File) + + " with non-abicalls file: " + toString(F.File)); if (!IsPic && IsPic2) - warn("linking non-abicalls code with abicalls file: " + F.Filename); + warn("linking non-abicalls code " + toString(Files[0].File) + + " with abicalls file: " + toString(F.File)); } // Compute the result PIC/non-PIC flag. @@ -221,10 +223,6 @@ static StringRef getMachName(uint32_t Flags) { } static StringRef getArchName(uint32_t Flags) { - StringRef S = getMachName(Flags); - if (!S.empty()) - return S; - switch (Flags & EF_MIPS_ARCH) { case EF_MIPS_ARCH_1: return "mips1"; @@ -253,6 +251,14 @@ static StringRef getArchName(uint32_t Flags) { } } +static std::string getFullArchName(uint32_t Flags) { + StringRef Arch = getArchName(Flags); + StringRef Mach = getMachName(Flags); + if (Mach.empty()) + return Arch.str(); + return (Arch + " (" + Mach + ")").str(); +} + // There are (arguably too) many MIPS ISAs out there. Their relationships // can be represented as a forest. If all input files have ISAs which // reachable by repeated proceeding from the single child to the parent, @@ -272,8 +278,9 @@ static uint32_t getArchFlags(ArrayRef<FileFlags> Files) { if (isArchMatched(New, Ret)) continue; if (!isArchMatched(Ret, New)) { - error("target ISA '" + getArchName(Ret) + "' is incompatible with '" + - getArchName(New) + "': " + F.Filename); + error("incompatible target ISA:\n>>> " + toString(Files[0].File) + ": " + + getFullArchName(Ret) + "\n>>> " + toString(F.File) + ": " + + getFullArchName(New)); return 0; } Ret = New; @@ -281,10 +288,10 @@ static uint32_t getArchFlags(ArrayRef<FileFlags> Files) { return Ret; } -template <class ELFT> uint32_t elf::getMipsEFlags() { +template <class ELFT> uint32_t elf::calcMipsEFlags() { std::vector<FileFlags> V; - for (elf::ObjectFile<ELFT> *F : Symtab<ELFT>::X->getObjectFiles()) - V.push_back({F->getName(), F->getObj().getHeader()->e_flags}); + for (InputFile *F : ObjectFiles) + V.push_back({F, cast<ObjFile<ELFT>>(F)->getObj().getHeader()->e_flags}); if (V.empty()) return 0; checkFlags(V); @@ -363,7 +370,14 @@ bool elf::isMipsN32Abi(const InputFile *F) { } } -template uint32_t elf::getMipsEFlags<ELF32LE>(); -template uint32_t elf::getMipsEFlags<ELF32BE>(); -template uint32_t elf::getMipsEFlags<ELF64LE>(); -template uint32_t elf::getMipsEFlags<ELF64BE>(); +bool elf::isMicroMips() { return Config->EFlags & EF_MIPS_MICROMIPS; } + +bool elf::isMipsR6() { + uint32_t Arch = Config->EFlags & EF_MIPS_ARCH; + return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6; +} + +template uint32_t elf::calcMipsEFlags<ELF32LE>(); +template uint32_t elf::calcMipsEFlags<ELF32BE>(); +template uint32_t elf::calcMipsEFlags<ELF64LE>(); +template uint32_t elf::calcMipsEFlags<ELF64BE>(); diff --git a/ELF/Arch/PPC.cpp b/ELF/Arch/PPC.cpp index 19e10729a00e..6af0df331df6 100644 --- a/ELF/Arch/PPC.cpp +++ b/ELF/Arch/PPC.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "Symbols.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; @@ -22,17 +22,33 @@ namespace { class PPC final : public TargetInfo { public: PPC() { GotBaseSymOff = 0x8000; } - void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; }; } // namespace -void PPC::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +RelExpr PPC::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { + switch (Type) { + case R_PPC_REL24: + case R_PPC_REL32: + return R_PC; + case R_PPC_PLTREL24: + return R_PLT_PC; + default: + return R_ABS; + } +} + +void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_PPC_ADDR16_HA: write16be(Loc, (Val + 0x8000) >> 16); break; + case R_PPC_ADDR16_HI: + write16be(Loc, Val >> 16); + break; case R_PPC_ADDR16_LO: write16be(Loc, Val); break; @@ -40,6 +56,7 @@ void PPC::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { case R_PPC_REL32: write32be(Loc, Val); break; + case R_PPC_PLTREL24: case R_PPC_REL24: write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC)); break; @@ -48,17 +65,6 @@ void PPC::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { } } -RelExpr PPC::getRelExpr(uint32_t Type, const SymbolBody &S, - const uint8_t *Loc) const { - switch (Type) { - case R_PPC_REL24: - case R_PPC_REL32: - return R_PC; - default: - return R_ABS; - } -} - TargetInfo *elf::getPPCTargetInfo() { static PPC Target; return &Target; diff --git a/ELF/Arch/PPC64.cpp b/ELF/Arch/PPC64.cpp index bf414d75bec7..ac4021b5918d 100644 --- a/ELF/Arch/PPC64.cpp +++ b/ELF/Arch/PPC64.cpp @@ -7,10 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; @@ -39,11 +39,11 @@ namespace { class PPC64 final : public TargetInfo { public: PPC64(); - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; - void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace @@ -82,11 +82,9 @@ PPC64::PPC64() { DefaultImageBase = 0x10000000; } -RelExpr PPC64::getRelExpr(uint32_t Type, const SymbolBody &S, +RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { - default: - return R_ABS; case R_PPC64_TOC16: case R_PPC64_TOC16_DS: case R_PPC64_TOC16_HA: @@ -98,6 +96,8 @@ RelExpr PPC64::getRelExpr(uint32_t Type, const SymbolBody &S, return R_PPC_TOC; case R_PPC64_REL24: return R_PPC_PLT_OPD; + default: + return R_ABS; } } @@ -122,7 +122,7 @@ void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, write32be(Buf + 28, 0x4e800420); // bctr } -static std::pair<uint32_t, uint64_t> toAddr16Rel(uint32_t Type, uint64_t Val) { +static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) { uint64_t V = Val - PPC64TocOffset; switch (Type) { case R_PPC64_TOC16: @@ -142,7 +142,7 @@ static std::pair<uint32_t, uint64_t> toAddr16Rel(uint32_t Type, uint64_t Val) { } } -void PPC64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { // For a TOC-relative relocation, proceed in terms of the corresponding // ADDR16 relocation type. std::tie(Type, Val) = toAddr16Rel(Type, Val); diff --git a/ELF/Arch/SPARCV9.cpp b/ELF/Arch/SPARCV9.cpp index 1f977c1e9cf2..d9d6e1390407 100644 --- a/ELF/Arch/SPARCV9.cpp +++ b/ELF/Arch/SPARCV9.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; @@ -24,11 +24,11 @@ namespace { class SPARCV9 final : public TargetInfo { public: SPARCV9(); - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; - void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace @@ -46,7 +46,7 @@ SPARCV9::SPARCV9() { DefaultImageBase = 0x100000; } -RelExpr SPARCV9::getRelExpr(uint32_t Type, const SymbolBody &S, +RelExpr SPARCV9::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { case R_SPARC_32: @@ -68,12 +68,11 @@ RelExpr SPARCV9::getRelExpr(uint32_t Type, const SymbolBody &S, case R_SPARC_NONE: return R_NONE; default: - error(toString(S.File) + ": unknown relocation type: " + toString(Type)); - return R_HINT; + return R_INVALID; } } -void SPARCV9::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +void SPARCV9::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_SPARC_32: case R_SPARC_UA32: diff --git a/ELF/Arch/X86.cpp b/ELF/Arch/X86.cpp index a1e9bcaf1b12..fc848917d4e9 100644 --- a/ELF/Arch/X86.cpp +++ b/ELF/Arch/X86.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; @@ -24,24 +24,24 @@ namespace { class X86 final : public TargetInfo { public: X86(); - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; - int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; + int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; - uint32_t getDynRel(uint32_t Type) const override; - void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; - void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override; + RelType getDynRel(RelType Type) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; - void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; - RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr Expr) const override; - void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; - void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; - void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; - void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace @@ -63,7 +63,9 @@ X86::X86() { TrapInstr = 0xcccccccc; // 0xcc = INT3 } -RelExpr X86::getRelExpr(uint32_t Type, const SymbolBody &S, +static bool hasBaseReg(uint8_t ModRM) { return (ModRM & 0xc7) != 0x5; } + +RelExpr X86::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { case R_386_8: @@ -87,24 +89,42 @@ RelExpr X86::getRelExpr(uint32_t Type, const SymbolBody &S, return R_GOT; case R_386_GOT32: case R_386_GOT32X: - // These relocations can be calculated in two different ways. - // Usual calculation is G + A - GOT what means an offset in GOT table - // (R_GOT_FROM_END). When instruction pointed by relocation has no base - // register, then relocations can be used when PIC code is disabled. In that - // case calculation is G + A, it resolves to an address of entry in GOT - // (R_GOT) and not an offset. + // These relocations are arguably mis-designed because their calculations + // depend on the instructions they are applied to. This is bad because we + // usually don't care about whether the target section contains valid + // machine instructions or not. But this is part of the documented ABI, so + // we had to implement as the standard requires. // - // To check that instruction has no base register we scan ModR/M byte. - // See "Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte" - // (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/ - // 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf) - if ((Loc[-1] & 0xc7) != 0x5) - return R_GOT_FROM_END; - if (Config->Pic) - error(toString(S.File) + ": relocation " + toString(Type) + " against '" + - S.getName() + - "' without base register can not be used when PIC enabled"); - return R_GOT; + // x86 does not support PC-relative data access. Therefore, in order to + // access GOT contents, a GOT address needs to be known at link-time + // (which means non-PIC) or compilers have to emit code to get a GOT + // address at runtime (which means code is position-independent but + // compilers need to emit extra code for each GOT access.) This decision + // is made at compile-time. In the latter case, compilers emit code to + // load an GOT address to a register, which is usually %ebx. + // + // So, there are two ways to refer to symbol foo's GOT entry: foo@GOT or + // foo@GOT(%reg). + // + // foo@GOT is not usable in PIC. If we are creating a PIC output and if we + // find such relocation, we should report an error. foo@GOT is resolved to + // an *absolute* address of foo's GOT entry, because both GOT address and + // foo's offset are known. In other words, it's G + A. + // + // foo@GOT(%reg) needs to be resolved to a *relative* offset from a GOT to + // foo's GOT entry in the table, because GOT address is not known but foo's + // offset in the table is known. It's G + A - GOT. + // + // It's unfortunate that compilers emit the same relocation for these + // different use cases. In order to distinguish them, we have to read a + // machine instruction. + // + // The following code implements it. We assume that Loc[0] is the first + // byte of a displacement or an immediate field of a valid machine + // instruction. That means a ModRM byte is at Loc[-1]. By taking a look at + // the byte, we can determine whether the instruction is register-relative + // (i.e. it was generated for foo@GOT(%reg)) or absolute (i.e. foo@GOT). + return hasBaseReg(Loc[-1]) ? R_GOT_FROM_END : R_GOT; case R_386_TLS_GOTIE: return R_GOT_FROM_END; case R_386_GOTOFF: @@ -116,12 +136,11 @@ RelExpr X86::getRelExpr(uint32_t Type, const SymbolBody &S, case R_386_NONE: return R_NONE; default: - error(toString(S.File) + ": unknown relocation type: " + toString(Type)); - return R_HINT; + return R_INVALID; } } -RelExpr X86::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, +RelExpr X86::adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr Expr) const { switch (Expr) { default: @@ -137,18 +156,18 @@ void X86::writeGotPltHeader(uint8_t *Buf) const { write32le(Buf, InX::Dynamic->getVA()); } -void X86::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const { +void X86::writeGotPlt(uint8_t *Buf, const Symbol &S) const { // Entries in .got.plt initially points back to the corresponding // PLT entries with a fixed offset to skip the first instruction. write32le(Buf, S.getPltVA() + 6); } -void X86::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const { +void X86::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { // An x86 entry is the address of the ifunc resolver function. write32le(Buf, S.getVA()); } -uint32_t X86::getDynRel(uint32_t Type) const { +RelType X86::getDynRel(RelType Type) const { if (Type == R_386_TLS_LE) return R_386_TLS_TPOFF; if (Type == R_386_TLS_LE_32) @@ -208,10 +227,8 @@ void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); } -int64_t X86::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { +int64_t X86::getImplicitAddend(const uint8_t *Buf, RelType Type) const { switch (Type) { - default: - return 0; case R_386_8: case R_386_PC8: return SignExtend64<8>(*Buf); @@ -228,15 +245,17 @@ int64_t X86::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { case R_386_TLS_LDO_32: case R_386_TLS_LE: return SignExtend64<32>(read32le(Buf)); + default: + return 0; } } -void X86::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { - // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are - // being used for some 16-bit programs such as boot loaders, so - // we want to support them. +void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_386_8: + // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are + // being used for some 16-bit programs such as boot loaders, so + // we want to support them. checkUInt<8>(Loc, Val, Type); *Loc = Val; break; @@ -262,13 +281,35 @@ void X86::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { checkInt<17>(Loc, Val, Type); write16le(Loc, Val); break; - default: + case R_386_32: + case R_386_GLOB_DAT: + case R_386_GOT32: + case R_386_GOT32X: + case R_386_GOTOFF: + case R_386_GOTPC: + case R_386_PC32: + case R_386_PLT32: + case R_386_RELATIVE: + case R_386_TLS_DTPMOD32: + case R_386_TLS_DTPOFF32: + case R_386_TLS_GD: + case R_386_TLS_GOTIE: + case R_386_TLS_IE: + case R_386_TLS_LDM: + case R_386_TLS_LDO_32: + case R_386_TLS_LE: + case R_386_TLS_LE_32: + case R_386_TLS_TPOFF: + case R_386_TLS_TPOFF32: checkInt<32>(Loc, Val, Type); write32le(Loc, Val); + break; + default: + error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } -void X86::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +void X86::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Convert // leal x@tlsgd(, %ebx, 1), // call __tls_get_addr@plt @@ -283,7 +324,7 @@ void X86::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { write32le(Loc + 5, Val); } -void X86::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +void X86::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Convert // leal x@tlsgd(, %ebx, 1), // call __tls_get_addr@plt @@ -300,7 +341,7 @@ void X86::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // In some conditions, relocations can be optimized to avoid using GOT. // This function does that for Initial Exec to Local Exec case. -void X86::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +void X86::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Ulrich's document section 6.2 says that @gotntpoff can // be used with MOVL or ADDL instructions. // @indntpoff is similar to @gotntpoff, but for use in @@ -337,7 +378,7 @@ void X86::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { write32le(Loc, Val); } -void X86::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { +void X86::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { if (Type == R_386_TLS_LDO_32) { write32le(Loc, Val); return; diff --git a/ELF/Arch/X86_64.cpp b/ELF/Arch/X86_64.cpp index 10179f57ee93..14e354b9f4fb 100644 --- a/ELF/Arch/X86_64.cpp +++ b/ELF/Arch/X86_64.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" @@ -26,23 +26,23 @@ namespace { template <class ELFT> class X86_64 final : public TargetInfo { public: X86_64(); - RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; - bool isPicRel(uint32_t Type) const override; + bool isPicRel(RelType Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; - void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; - void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; - RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr Expr) const override; void relaxGot(uint8_t *Loc, uint64_t Val) const override; - void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; - void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; - void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; - void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; + void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; private: void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, @@ -73,7 +73,7 @@ template <class ELFT> X86_64<ELFT>::X86_64() { } template <class ELFT> -RelExpr X86_64<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S, +RelExpr X86_64<ELFT>::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { case R_X86_64_8: @@ -109,8 +109,7 @@ RelExpr X86_64<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S, case R_X86_64_NONE: return R_NONE; default: - error(toString(S.File) + ": unknown relocation type: " + toString(Type)); - return R_HINT; + return R_INVALID; } } @@ -123,8 +122,8 @@ template <class ELFT> void X86_64<ELFT>::writeGotPltHeader(uint8_t *Buf) const { } template <class ELFT> -void X86_64<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const { - // See comments in X86TargetInfo::writeGotPlt. +void X86_64<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + // See comments in X86::writeGotPlt. write32le(Buf, S.getPltVA() + 6); } @@ -157,13 +156,13 @@ void X86_64<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); } -template <class ELFT> bool X86_64<ELFT>::isPicRel(uint32_t Type) const { +template <class ELFT> bool X86_64<ELFT>::isPicRel(RelType Type) const { return Type != R_X86_64_PC32 && Type != R_X86_64_32 && Type != R_X86_64_TPOFF32; } template <class ELFT> -void X86_64<ELFT>::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, +void X86_64<ELFT>::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Convert // .byte 0x66 @@ -186,7 +185,7 @@ void X86_64<ELFT>::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, } template <class ELFT> -void X86_64<ELFT>::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, +void X86_64<ELFT>::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Convert // .byte 0x66 @@ -211,7 +210,7 @@ void X86_64<ELFT>::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, // In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to // R_X86_64_TPOFF32 so that it does not use GOT. template <class ELFT> -void X86_64<ELFT>::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, +void X86_64<ELFT>::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { uint8_t *Inst = Loc - 3; uint8_t Reg = Loc[-1] >> 3; @@ -254,7 +253,7 @@ void X86_64<ELFT>::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, } template <class ELFT> -void X86_64<ELFT>::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, +void X86_64<ELFT>::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // Convert // leaq bar@tlsld(%rip), %rdi @@ -283,8 +282,7 @@ void X86_64<ELFT>::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, } template <class ELFT> -void X86_64<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, - uint64_t Val) const { +void X86_64<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_X86_64_8: checkUInt<8>(Loc, Val, Type); @@ -323,12 +321,12 @@ void X86_64<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, write64le(Loc, Val); break; default: - llvm_unreachable("unexpected relocation"); + error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } template <class ELFT> -RelExpr X86_64<ELFT>::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, +RelExpr X86_64<ELFT>::adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr RelExpr) const { if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX) return RelExpr; diff --git a/ELF/Bits.h b/ELF/Bits.h new file mode 100644 index 000000000000..13d40322265e --- /dev/null +++ b/ELF/Bits.h @@ -0,0 +1,35 @@ +//===- Bits.h ---------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_BITS_H +#define LLD_ELF_BITS_H + +#include "Config.h" +#include "llvm/Support/Endian.h" + +namespace lld { +namespace elf { + +inline uint64_t readUint(uint8_t *Buf) { + if (Config->Is64) + return llvm::support::endian::read64(Buf, Config->Endianness); + return llvm::support::endian::read32(Buf, Config->Endianness); +} + +inline void writeUint(uint8_t *Buf, uint64_t Val) { + if (Config->Is64) + llvm::support::endian::write64(Buf, Val, Config->Endianness); + else + llvm::support::endian::write32(Buf, Val, Config->Endianness); +} + +} // namespace elf +} // namespace lld + +#endif diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt index 77243bd494d1..7ec837841315 100644 --- a/ELF/CMakeLists.txt +++ b/ELF/CMakeLists.txt @@ -7,6 +7,7 @@ if(NOT LLD_BUILT_STANDALONE) endif() add_lld_library(lldELF + AArch64ErrataFix.cpp Arch/AArch64.cpp Arch/AMDGPU.cpp Arch/ARM.cpp @@ -21,7 +22,6 @@ add_lld_library(lldELF Driver.cpp DriverUtils.cpp EhFrame.cpp - Error.cpp Filesystem.cpp GdbIndex.cpp ICF.cpp @@ -45,28 +45,17 @@ add_lld_library(lldELF LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} - Analysis BinaryFormat - BitReader - BitWriter - Codegen Core DebugInfoDWARF - Demangle - IPO - Linker LTO + MC Object Option - Passes - MC Support - Target - TransformUtils LINK_LIBS - lldConfig - lldCore + lldCommon ${LLVM_PTHREAD_LIB} DEPENDS diff --git a/ELF/Config.h b/ELF/Config.h index 23627dd812db..74c325cb7cb1 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -24,7 +24,6 @@ namespace lld { namespace elf { class InputFile; -struct Symbol; enum ELFKind { ELFNoneKind, @@ -44,7 +43,10 @@ enum class DiscardPolicy { Default, All, Locals, None }; enum class StripPolicy { None, All, Debug }; // For --unresolved-symbols. -enum class UnresolvedPolicy { ReportError, Warn, WarnAll, Ignore, IgnoreAll }; +enum class UnresolvedPolicy { ReportError, Warn, Ignore, IgnoreAll }; + +// For --orphan-handling. +enum class OrphanHandlingPolicy { Place, Warn, Error }; // For --sort-section and linkerscript sorting rules. enum class SortSectionPolicy { Default, None, Alignment, Name, Priority }; @@ -67,21 +69,15 @@ struct VersionDefinition { size_t NameOff = 0; // Offset in the string table }; -// Structure for mapping renamed symbols -struct RenamedSymbol { - Symbol *Target; - uint8_t OriginalBinding; -}; - // This struct contains the global configuration for the linker. // Most fields are direct mapping from the command line options // and such fields have the same name as the corresponding options. // Most fields are initialized by the driver. struct Configuration { - InputFile *FirstElf = nullptr; uint8_t OSABI = 0; llvm::CachePruningPolicy ThinLTOCachePolicy; llvm::StringMap<uint64_t> SectionStartMap; + llvm::StringRef Chroot; llvm::StringRef DynamicLinker; llvm::StringRef Entry; llvm::StringRef Emulation; @@ -103,15 +99,18 @@ struct Configuration { std::vector<llvm::StringRef> SearchPaths; std::vector<llvm::StringRef> SymbolOrderingFile; std::vector<llvm::StringRef> Undefined; + std::vector<SymbolVersion> DynamicList; std::vector<SymbolVersion> VersionScriptGlobals; std::vector<SymbolVersion> VersionScriptLocals; std::vector<uint8_t> BuildIdVector; - llvm::MapVector<Symbol *, RenamedSymbol> RenamedSymbols; bool AllowMultipleDefinition; + bool AndroidPackDynRelocs = false; + bool ARMHasBlx = false; + bool ARMHasMovtMovw = false; + bool ARMJ1J2BranchEncoding = false; bool AsNeeded = false; bool Bsymbolic; bool BsymbolicFunctions; - bool ColorDiagnostics = false; bool CompressDebugSections; bool DefineCommon; bool Demangle = true; @@ -120,14 +119,19 @@ struct Configuration { bool EmitRelocs; bool EnableNewDtags; bool ExportDynamic; - bool FatalWarnings; + bool FixCortexA53Errata843419; bool GcSections; bool GdbIndex; - bool GnuHash; + bool GnuHash = false; + bool HasDynamicList = false; + bool HasDynSymTab; bool ICF; + bool ICFData; + bool MergeArmExidx; bool MipsN32Abi = false; bool NoGnuUnique; bool NoUndefinedVersion; + bool NoinhibitExec; bool Nostdlib; bool OFormatBinary; bool Omagic; @@ -139,9 +143,8 @@ struct Configuration { bool SingleRoRx; bool Shared; bool Static = false; - bool SysvHash; + bool SysvHash = false; bool Target1Rel; - bool Threads; bool Trace; bool Verbose; bool WarnCommon; @@ -159,6 +162,7 @@ struct Configuration { bool ExitEarly; bool ZWxneeded; DiscardPolicy Discard; + OrphanHandlingPolicy OrphanHandling; SortSectionPolicy SortSection; StripPolicy Strip; UnresolvedPolicy UnresolvedSymbols; @@ -167,8 +171,7 @@ struct Configuration { ELFKind EKind = ELFNoneKind; uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; uint16_t EMachine = llvm::ELF::EM_NONE; - uint64_t ErrorLimit = 20; - uint64_t ImageBase; + llvm::Optional<uint64_t> ImageBase; uint64_t MaxPageSize; uint64_t ZStackSize; unsigned LTOPartitions; @@ -206,6 +209,9 @@ struct Configuration { // if that's true.) bool IsMips64EL; + // Holds set of ELF header flags for the target. + uint32_t EFlags = 0; + // The ELF spec defines two types of relocation table entries, RELA and // REL. RELA is a triplet of (offset, info, addend) while REL is a // tuple of (offset, info). Addends for REL are implicit and read from diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 47a50bb725e7..2b6925031b07 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -25,23 +25,25 @@ #include "Driver.h" #include "Config.h" -#include "Error.h" #include "Filesystem.h" #include "ICF.h" #include "InputFiles.h" #include "InputSection.h" #include "LinkerScript.h" -#include "Memory.h" #include "OutputSections.h" #include "ScriptParser.h" #include "Strings.h" #include "SymbolTable.h" +#include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" -#include "Threads.h" #include "Writer.h" -#include "lld/Config/Version.h" -#include "lld/Driver/Driver.h" +#include "lld/Common/Args.h" +#include "lld/Common/Driver.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" +#include "lld/Common/Threads.h" +#include "lld/Common/Version.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" @@ -64,27 +66,40 @@ using namespace lld::elf; Configuration *elf::Config; LinkerDriver *elf::Driver; -BumpPtrAllocator elf::BAlloc; -StringSaver elf::Saver{BAlloc}; -std::vector<SpecificAllocBase *> elf::SpecificAllocBase::Instances; - static void setConfigs(); bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Error) { - ErrorCount = 0; - ErrorOS = &Error; + errorHandler().LogName = Args[0]; + errorHandler().ErrorLimitExceededMsg = + "too many errors emitted, stopping now (use " + "-error-limit=0 to see all errors)"; + errorHandler().ErrorOS = &Error; + errorHandler().ColorDiagnostics = Error.has_colors(); InputSections.clear(); + OutputSections.clear(); Tar = nullptr; + BinaryFiles.clear(); + BitcodeFiles.clear(); + ObjectFiles.clear(); + SharedFiles.clear(); Config = make<Configuration>(); Driver = make<LinkerDriver>(); Script = make<LinkerScript>(); + Symtab = make<SymbolTable>(); Config->Argv = {Args.begin(), Args.end()}; Driver->main(Args, CanExitEarly); + + // Exit immediately if we don't need to return to the caller. + // This saves time because the overhead of calling destructors + // for all globally-allocated objects is not negligible. + if (Config->ExitEarly) + exitLld(errorCount() ? 1 : 0); + freeArena(); - return !ErrorCount; + return !errorCount(); } // Parses a linker -m option. @@ -112,12 +127,8 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) { .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) .Default({ELFNoneKind, EM_NONE}); - if (Ret.first == ELFNoneKind) { - if (S == "i386pe" || S == "i386pep" || S == "thumb2pe") - error("Windows targets are not supported on the ELF frontend: " + Emul); - else - error("unknown emulation: " + Emul); - } + if (Ret.first == ELFNoneKind) + error("unknown emulation: " + Emul); return std::make_tuple(Ret.first, Ret.second, OSABI); } @@ -126,19 +137,22 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) { std::vector<std::pair<MemoryBufferRef, uint64_t>> static getArchiveMembers( MemoryBufferRef MB) { std::unique_ptr<Archive> File = - check(Archive::create(MB), + CHECK(Archive::create(MB), MB.getBufferIdentifier() + ": failed to parse archive"); std::vector<std::pair<MemoryBufferRef, uint64_t>> V; Error Err = Error::success(); + bool AddToTar = File->isThin() && Tar; for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) { Archive::Child C = - check(COrErr, MB.getBufferIdentifier() + + CHECK(COrErr, MB.getBufferIdentifier() + ": could not get the child of the archive"); MemoryBufferRef MBRef = - check(C.getMemoryBufferRef(), + CHECK(C.getMemoryBufferRef(), MB.getBufferIdentifier() + ": could not get the buffer for a child of the archive"); + if (AddToTar) + Tar->append(relativeToRoot(check(C.getFullName())), MBRef.getBuffer()); V.push_back(std::make_pair(MBRef, C.getChildOffset())); } if (Err) @@ -179,7 +193,7 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { } std::unique_ptr<Archive> File = - check(Archive::create(MBRef), Path + ": failed to parse archive"); + CHECK(Archive::create(MBRef), Path + ": failed to parse archive"); // If an archive file has no symbol table, it is likely that a user // is attempting LTO and using a default ar command that doesn't @@ -187,7 +201,7 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { // we'll handle it as if it had a symbol table. if (!File->isEmpty() && !File->hasSymbolTable()) { for (const auto &P : getArchiveMembers(MBRef)) - Files.push_back(make<LazyObjectFile>(P.first, Path, P.second)); + Files.push_back(make<LazyObjFile>(P.first, Path, P.second)); return; } @@ -216,7 +230,7 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { return; default: if (InLib) - Files.push_back(make<LazyObjectFile>(MBRef, "", 0)); + Files.push_back(make<LazyObjFile>(MBRef, "", 0)); else Files.push_back(createObjectFile(MBRef)); } @@ -256,6 +270,9 @@ static void checkOptions(opt::InputArgList &Args) { if (Config->EMachine == EM_MIPS && Config->GnuHash) error("the .gnu.hash section is not compatible with the MIPS target."); + if (Config->FixCortexA53Errata843419 && Config->EMachine != EM_AARCH64) + error("--fix-cortex-a53-843419 is only supported on AArch64 targets."); + if (Config->Pie && Config->Shared) error("-shared and -pie may not be used together"); @@ -265,6 +282,9 @@ static void checkOptions(opt::InputArgList &Args) { if (!Config->Shared && !Config->AuxiliaryList.empty()) error("-f may not be used without -shared"); + if (!Config->Relocatable && !Config->DefineCommon) + error("-no-define-common not supported in non relocatable output"); + if (Config->Relocatable) { if (Config->Shared) error("-r and -shared may not be used together"); @@ -277,16 +297,6 @@ static void checkOptions(opt::InputArgList &Args) { } } -static int getInteger(opt::InputArgList &Args, unsigned Key, int Default) { - int V = Default; - if (auto *Arg = Args.getLastArg(Key)) { - StringRef S = Arg->getValue(); - if (!to_integer(S, V, 10)) - error(Arg->getSpelling() + ": number expected, but got " + S); - } - return V; -} - static const char *getReproduceOption(opt::InputArgList &Args) { if (auto *Arg = Args.getLastArg(OPT_reproduce)) return Arg->getValue(); @@ -300,26 +310,12 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) { return false; } -static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key, - uint64_t Default) { - for (auto *Arg : Args.filtered(OPT_z)) { - std::pair<StringRef, StringRef> KV = StringRef(Arg->getValue()).split('='); - if (KV.first == Key) { - uint64_t Result = Default; - if (!to_integer(KV.second, Result)) - error("invalid " + Key + ": " + KV.second); - return Result; - } - } - return Default; -} - void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { ELFOptTable Parser; opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); // Interpret this flag early because error() depends on them. - Config->ErrorLimit = getInteger(Args, OPT_error_limit, 20); + errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20); // Handle -help if (Args.hasArg(OPT_help)) { @@ -345,13 +341,15 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version)) message(getLLDVersion() + " (compatible with GNU linkers)"); - // ld.bfd always exits after printing out the version string. - // ld.gold proceeds if a given option is -v. Because gold's behavior - // is more permissive than ld.bfd, we chose what gold does here. + // The behavior of -v or --version is a bit strange, but this is + // needed for compatibility with GNU linkers. + if (Args.hasArg(OPT_v) && !Args.hasArg(OPT_INPUT)) + return; if (Args.hasArg(OPT_version)) return; Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown); + errorHandler().ExitEarly = Config->ExitEarly; if (const char *Path = getReproduceOption(Args)) { // Note that --reproduce is a debug option so you can ignore it @@ -375,7 +373,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { inferMachineType(); setConfigs(); checkOptions(Args); - if (ErrorCount) + if (errorCount()) return; switch (Config->EKind) { @@ -396,36 +394,19 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { } } -static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2, - bool Default) { - if (auto *Arg = Args.getLastArg(K1, K2)) - return Arg->getOption().getID() == K1; - return Default; -} - -static std::vector<StringRef> getArgs(opt::InputArgList &Args, int Id) { - std::vector<StringRef> V; - for (auto *Arg : Args.filtered(Id)) - V.push_back(Arg->getValue()); - return V; -} - static std::string getRpath(opt::InputArgList &Args) { - std::vector<StringRef> V = getArgs(Args, OPT_rpath); + std::vector<StringRef> V = args::getStrings(Args, OPT_rpath); return llvm::join(V.begin(), V.end(), ":"); } // Determines what we should do if there are remaining unresolved // symbols after the name resolution. static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) { - // -noinhibit-exec or -r imply some default values. - if (Args.hasArg(OPT_noinhibit_exec)) - return UnresolvedPolicy::WarnAll; if (Args.hasArg(OPT_relocatable)) return UnresolvedPolicy::IgnoreAll; - UnresolvedPolicy ErrorOrWarn = getArg(Args, OPT_error_unresolved_symbols, - OPT_warn_unresolved_symbols, true) + UnresolvedPolicy ErrorOrWarn = Args.hasFlag(OPT_error_unresolved_symbols, + OPT_warn_unresolved_symbols, true) ? UnresolvedPolicy::ReportError : UnresolvedPolicy::Warn; @@ -513,7 +494,7 @@ static StripPolicy getStrip(opt::InputArgList &Args) { return StripPolicy::Debug; } -static uint64_t parseSectionAddress(StringRef S, opt::Arg *Arg) { +static uint64_t parseSectionAddress(StringRef S, const opt::Arg &Arg) { uint64_t VA = 0; if (S.startswith("0x")) S = S.drop_front(2); @@ -528,15 +509,15 @@ static StringMap<uint64_t> getSectionStartMap(opt::InputArgList &Args) { StringRef Name; StringRef Addr; std::tie(Name, Addr) = StringRef(Arg->getValue()).split('='); - Ret[Name] = parseSectionAddress(Addr, Arg); + Ret[Name] = parseSectionAddress(Addr, *Arg); } if (auto *Arg = Args.getLastArg(OPT_Ttext)) - Ret[".text"] = parseSectionAddress(Arg->getValue(), Arg); + Ret[".text"] = parseSectionAddress(Arg->getValue(), *Arg); if (auto *Arg = Args.getLastArg(OPT_Tdata)) - Ret[".data"] = parseSectionAddress(Arg->getValue(), Arg); + Ret[".data"] = parseSectionAddress(Arg->getValue(), *Arg); if (auto *Arg = Args.getLastArg(OPT_Tbss)) - Ret[".bss"] = parseSectionAddress(Arg->getValue(), Arg); + Ret[".bss"] = parseSectionAddress(Arg->getValue(), *Arg); return Ret; } @@ -551,15 +532,15 @@ static SortSectionPolicy getSortSection(opt::InputArgList &Args) { return SortSectionPolicy::Default; } -static std::pair<bool, bool> getHashStyle(opt::InputArgList &Args) { - StringRef S = Args.getLastArgValue(OPT_hash_style, "sysv"); - if (S == "sysv") - return {true, false}; - if (S == "gnu") - return {false, true}; - if (S != "both") - error("unknown -hash-style: " + S); - return {true, true}; +static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &Args) { + StringRef S = Args.getLastArgValue(OPT_orphan_handling, "place"); + if (S == "warn") + return OrphanHandlingPolicy::Warn; + if (S == "error") + return OrphanHandlingPolicy::Error; + if (S != "place") + error("unknown --orphan-handling mode: " + S); + return OrphanHandlingPolicy::Place; } // Parse --build-id or --build-id=<style>. We handle "tree" as a @@ -589,19 +570,6 @@ getBuildId(opt::InputArgList &Args) { return {BuildIdKind::None, {}}; } -static std::vector<StringRef> getLines(MemoryBufferRef MB) { - SmallVector<StringRef, 0> Arr; - MB.getBuffer().split(Arr, '\n'); - - std::vector<StringRef> Ret; - for (StringRef S : Arr) { - S = S.trim(); - if (!S.empty()) - Ret.push_back(S); - } - return Ret; -} - static bool getCompressDebugSections(opt::InputArgList &Args) { StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none"); if (S == "none") @@ -613,53 +581,70 @@ static bool getCompressDebugSections(opt::InputArgList &Args) { return true; } +static int parseInt(StringRef S, opt::Arg *Arg) { + int V = 0; + if (!to_integer(S, V, 10)) + error(Arg->getSpelling() + ": number expected, but got '" + S + "'"); + return V; +} + // Initializes Config members by the command line options. void LinkerDriver::readConfigs(opt::InputArgList &Args) { - Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition); - Config->AuxiliaryList = getArgs(Args, OPT_auxiliary); + Config->AllowMultipleDefinition = + Args.hasArg(OPT_allow_multiple_definition) || hasZOption(Args, "muldefs"); + Config->AuxiliaryList = args::getStrings(Args, OPT_auxiliary); Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); + Config->Chroot = Args.getLastArgValue(OPT_chroot); Config->CompressDebugSections = getCompressDebugSections(Args); - Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common, - !Args.hasArg(OPT_relocatable)); - Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true); + Config->DefineCommon = Args.hasFlag(OPT_define_common, OPT_no_define_common, + !Args.hasArg(OPT_relocatable)); + Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true); Config->DisableVerify = Args.hasArg(OPT_disable_verify); Config->Discard = getDiscard(Args); Config->DynamicLinker = getDynamicLinker(Args); - Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr); + Config->EhFrameHdr = + Args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false); Config->EmitRelocs = Args.hasArg(OPT_emit_relocs); Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags); Config->Entry = Args.getLastArgValue(OPT_entry); Config->ExportDynamic = - getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false); - Config->FatalWarnings = - getArg(Args, OPT_fatal_warnings, OPT_no_fatal_warnings, false); - Config->FilterList = getArgs(Args, OPT_filter); + Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false); + errorHandler().FatalWarnings = + Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); + Config->FilterList = args::getStrings(Args, OPT_filter); Config->Fini = Args.getLastArgValue(OPT_fini, "_fini"); - Config->GcSections = getArg(Args, OPT_gc_sections, OPT_no_gc_sections, false); - Config->GdbIndex = Args.hasArg(OPT_gdb_index); - Config->ICF = getArg(Args, OPT_icf_all, OPT_icf_none, false); + Config->FixCortexA53Errata843419 = Args.hasArg(OPT_fix_cortex_a53_843419); + Config->GcSections = Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false); + Config->GdbIndex = Args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false); + Config->ICF = Args.hasFlag(OPT_icf_all, OPT_icf_none, false); + Config->ICFData = Args.hasArg(OPT_icf_data); Config->Init = Args.getLastArgValue(OPT_init, "_init"); Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline); Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes); - Config->LTOO = getInteger(Args, OPT_lto_O, 2); - Config->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1); + Config->LTOO = args::getInteger(Args, OPT_lto_O, 2); + Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1); Config->MapFile = Args.getLastArgValue(OPT_Map); Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique); + Config->MergeArmExidx = + Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true); Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version); + Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec); Config->Nostdlib = Args.hasArg(OPT_nostdlib); Config->OFormatBinary = isOutputFormatBinary(Args); - Config->Omagic = Args.hasArg(OPT_omagic); + Config->Omagic = Args.hasFlag(OPT_omagic, OPT_no_omagic, false); Config->OptRemarksFilename = Args.getLastArgValue(OPT_opt_remarks_filename); Config->OptRemarksWithHotness = Args.hasArg(OPT_opt_remarks_with_hotness); - Config->Optimize = getInteger(Args, OPT_O, 1); + Config->Optimize = args::getInteger(Args, OPT_O, 1); + Config->OrphanHandling = getOrphanHandling(Args); Config->OutputFile = Args.getLastArgValue(OPT_o); - Config->Pie = getArg(Args, OPT_pie, OPT_nopie, false); - Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections); + Config->Pie = Args.hasFlag(OPT_pie, OPT_nopie, false); + Config->PrintGcSections = + Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); Config->Rpath = getRpath(Args); Config->Relocatable = Args.hasArg(OPT_relocatable); Config->SaveTemps = Args.hasArg(OPT_save_temps); - Config->SearchPaths = getArgs(Args, OPT_L); + Config->SearchPaths = args::getStrings(Args, OPT_library_path); Config->SectionStartMap = getSectionStartMap(Args); Config->Shared = Args.hasArg(OPT_shared); Config->SingleRoRx = Args.hasArg(OPT_no_rosegment); @@ -667,18 +652,19 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->SortSection = getSortSection(Args); Config->Strip = getStrip(Args); Config->Sysroot = Args.getLastArgValue(OPT_sysroot); - Config->Target1Rel = getArg(Args, OPT_target1_rel, OPT_target1_abs, false); + Config->Target1Rel = Args.hasFlag(OPT_target1_rel, OPT_target1_abs, false); Config->Target2 = getTarget2(Args); Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir); - Config->ThinLTOCachePolicy = check( + Config->ThinLTOCachePolicy = CHECK( parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)), "--thinlto-cache-policy: invalid cache policy"); - Config->ThinLTOJobs = getInteger(Args, OPT_thinlto_jobs, -1u); - Config->Threads = getArg(Args, OPT_threads, OPT_no_threads, true); + Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u); + ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); Config->Trace = Args.hasArg(OPT_trace); - Config->Undefined = getArgs(Args, OPT_undefined); + Config->Undefined = args::getStrings(Args, OPT_undefined); Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args); Config->Verbose = Args.hasArg(OPT_verbose); + errorHandler().Verbose = Config->Verbose; Config->WarnCommon = Args.hasArg(OPT_warn_common); Config->ZCombreloc = !hasZOption(Args, "nocombreloc"); Config->ZExecstack = hasZOption(Args, "execstack"); @@ -689,20 +675,39 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->ZOrigin = hasZOption(Args, "origin"); Config->ZRelro = !hasZOption(Args, "norelro"); Config->ZRodynamic = hasZOption(Args, "rodynamic"); - Config->ZStackSize = getZOptionValue(Args, "stack-size", 0); + Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", 0); Config->ZText = !hasZOption(Args, "notext"); Config->ZWxneeded = hasZOption(Args, "wxneeded"); + // Parse LTO plugin-related options for compatibility with gold. + for (auto *Arg : Args.filtered(OPT_plugin_opt, OPT_plugin_opt_eq)) { + StringRef S = Arg->getValue(); + if (S == "disable-verify") + Config->DisableVerify = true; + else if (S == "save-temps") + Config->SaveTemps = true; + else if (S.startswith("O")) + Config->LTOO = parseInt(S.substr(1), Arg); + else if (S.startswith("lto-partitions=")) + Config->LTOPartitions = parseInt(S.substr(15), Arg); + else if (S.startswith("jobs=")) + Config->ThinLTOJobs = parseInt(S.substr(5), Arg); + else if (!S.startswith("/") && !S.startswith("-fresolution=") && + !S.startswith("-pass-through=") && !S.startswith("mcpu=") && + !S.startswith("thinlto") && S != "-function-sections" && + S != "-data-sections") + error(Arg->getSpelling() + ": unknown option: " + S); + } + if (Config->LTOO > 3) - error("invalid optimization level for LTO: " + - Args.getLastArgValue(OPT_lto_O)); + error("invalid optimization level for LTO: " + Twine(Config->LTOO)); if (Config->LTOPartitions == 0) error("--lto-partitions: number of threads must be > 0"); if (Config->ThinLTOJobs == 0) error("--thinlto-jobs: number of threads must be > 0"); + // Parse ELF{32,64}{LE,BE} and CPU type. if (auto *Arg = Args.getLastArg(OPT_m)) { - // Parse ELF{32,64}{LE,BE} and CPU type. StringRef S = Arg->getValue(); std::tie(Config->EKind, Config->EMachine, Config->OSABI) = parseEmulation(S); @@ -710,6 +715,19 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->Emulation = S; } + // Parse -hash-style={sysv,gnu,both}. + if (auto *Arg = Args.getLastArg(OPT_hash_style)) { + StringRef S = Arg->getValue(); + if (S == "sysv") + Config->SysvHash = true; + else if (S == "gnu") + Config->GnuHash = true; + else if (S == "both") + Config->SysvHash = Config->GnuHash = true; + else + error("unknown -hash-style: " + S); + } + if (Args.hasArg(OPT_print_map)) Config->MapFile = "-"; @@ -720,25 +738,32 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { if (Config->Omagic) Config->ZRelro = false; - std::tie(Config->SysvHash, Config->GnuHash) = getHashStyle(Args); std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args); + if (auto *Arg = Args.getLastArg(OPT_pack_dyn_relocs_eq)) { + StringRef S = Arg->getValue(); + if (S == "android") + Config->AndroidPackDynRelocs = true; + else if (S != "none") + error("unknown -pack-dyn-relocs format: " + S); + } + if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file)) if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) - Config->SymbolOrderingFile = getLines(*Buffer); + Config->SymbolOrderingFile = args::getLines(*Buffer); // If --retain-symbol-file is used, we'll keep only the symbols listed in // the file and discard all others. if (auto *Arg = Args.getLastArg(OPT_retain_symbols_file)) { Config->DefaultSymbolVersion = VER_NDX_LOCAL; if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) - for (StringRef S : getLines(*Buffer)) + for (StringRef S : args::getLines(*Buffer)) Config->VersionScriptGlobals.push_back( {S, /*IsExternCpp*/ false, /*HasWildcard*/ false}); } bool HasExportDynamic = - getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false); + Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false); // Parses -dynamic-list and -export-dynamic-symbol. They make some // symbols private. Note that -export-dynamic takes precedence over them @@ -749,21 +774,11 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { readDynamicList(*Buffer); for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) - Config->VersionScriptGlobals.push_back( + Config->DynamicList.push_back( {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false}); - - // Dynamic lists are a simplified linker script that doesn't need the - // "global:" and implicitly ends with a "local:*". Set the variables - // needed to simulate that. - if (Args.hasArg(OPT_dynamic_list) || - Args.hasArg(OPT_export_dynamic_symbol)) { - Config->ExportDynamic = true; - if (!Config->Shared) - Config->DefaultSymbolVersion = VER_NDX_LOCAL; - } } - if (auto *Arg = Args.getLastArg(OPT_version_script)) + for (auto *Arg : Args.filtered(OPT_version_script)) if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) readVersionScript(*Buffer); } @@ -804,17 +819,20 @@ static bool getBinaryOption(StringRef S) { void LinkerDriver::createFiles(opt::InputArgList &Args) { for (auto *Arg : Args) { - switch (Arg->getOption().getID()) { - case OPT_l: + switch (Arg->getOption().getUnaliasedOption().getID()) { + case OPT_library: addLibrary(Arg->getValue()); break; case OPT_INPUT: addFile(Arg->getValue(), /*WithLOption=*/false); break; - case OPT_alias_script_T: case OPT_script: - if (Optional<MemoryBufferRef> MB = readFile(Arg->getValue())) - readLinkerScript(*MB); + if (Optional<std::string> Path = searchLinkerScript(Arg->getValue())) { + if (Optional<MemoryBufferRef> MB = readFile(*Path)) + readLinkerScript(*MB); + break; + } + error(Twine("cannot find linker script ") + Arg->getValue()); break; case OPT_as_needed: Config->AsNeeded = true; @@ -846,7 +864,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { } } - if (Files.empty() && ErrorCount == 0) + if (Files.empty() && errorCount() == 0) error("no input files"); } @@ -870,21 +888,20 @@ void LinkerDriver::inferMachineType() { // Parse -z max-page-size=<value>. The default value is defined by // each target. static uint64_t getMaxPageSize(opt::InputArgList &Args) { - uint64_t Val = - getZOptionValue(Args, "max-page-size", Target->DefaultMaxPageSize); + uint64_t Val = args::getZOptionValue(Args, OPT_z, "max-page-size", + Target->DefaultMaxPageSize); if (!isPowerOf2_64(Val)) error("max-page-size: value isn't a power of 2"); return Val; } // Parses -image-base option. -static uint64_t getImageBase(opt::InputArgList &Args) { - // Use default if no -image-base option is given. - // Because we are using "Target" here, this function - // has to be called after the variable is initialized. +static Optional<uint64_t> getImageBase(opt::InputArgList &Args) { + // Because we are using "Config->MaxPageSize" here, this function has to be + // called after the variable is initialized. auto *Arg = Args.getLastArg(OPT_image_base); if (!Arg) - return Config->Pic ? 0 : Target->DefaultImageBase; + return None; StringRef S = Arg->getValue(); uint64_t V; @@ -897,21 +914,6 @@ static uint64_t getImageBase(opt::InputArgList &Args) { return V; } -// Parses --defsym=alias option. -static std::vector<std::pair<StringRef, StringRef>> -getDefsym(opt::InputArgList &Args) { - std::vector<std::pair<StringRef, StringRef>> Ret; - for (auto *Arg : Args.filtered(OPT_defsym)) { - StringRef From; - StringRef To; - std::tie(From, To) = StringRef(Arg->getValue()).split('='); - if (!isValidCIdentifier(To)) - error("--defsym: symbol name expected, but got " + To); - Ret.push_back({From, To}); - } - return Ret; -} - // Parses `--exclude-libs=lib,lib,...`. // The library names may be delimited by commas or colons. static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) { @@ -930,33 +932,50 @@ static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) { return Ret; } +static Optional<StringRef> getArchiveName(InputFile *File) { + if (isa<ArchiveFile>(File)) + return File->getName(); + if (!File->ArchiveName.empty()) + return File->ArchiveName; + return None; +} + // Handles the -exclude-libs option. If a static library file is specified // by the -exclude-libs option, all public symbols from the archive become // private unless otherwise specified by version scripts or something. // A special library name "ALL" means all archive files. // // This is not a popular option, but some programs such as bionic libc use it. +template <class ELFT> static void excludeLibs(opt::InputArgList &Args, ArrayRef<InputFile *> Files) { DenseSet<StringRef> Libs = getExcludeLibs(Args); bool All = Libs.count("ALL"); for (InputFile *File : Files) - if (auto *F = dyn_cast<ArchiveFile>(File)) - if (All || Libs.count(path::filename(F->getName()))) - for (Symbol *Sym : F->getSymbols()) - Sym->VersionId = VER_NDX_LOCAL; + if (Optional<StringRef> Archive = getArchiveName(File)) + if (All || Libs.count(path::filename(*Archive))) + for (Symbol *Sym : File->getSymbols()) + if (!Sym->isLocal()) + Sym->VersionId = VER_NDX_LOCAL; } // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { - SymbolTable<ELFT> Symtab; - elf::Symtab<ELFT>::X = &Symtab; Target = getTarget(); Config->MaxPageSize = getMaxPageSize(Args); Config->ImageBase = getImageBase(Args); + // If a -hash-style option was not given, set to a default value, + // which varies depending on the target. + if (!Args.hasArg(OPT_hash_style)) { + if (Config->EMachine == EM_MIPS) + Config->SysvHash = true; + else + Config->SysvHash = Config->GnuHash = true; + } + // Default output filename is "a.out" by the Unix tradition. if (Config->OutputFile.empty()) Config->OutputFile = "a.out"; @@ -968,7 +987,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { error("cannot open output file " + Config->OutputFile + ": " + E.message()); if (auto E = tryCreateFile(Config->MapFile)) error("cannot open map file " + Config->MapFile + ": " + E.message()); - if (ErrorCount) + if (errorCount()) return; // Use default entry point name if no name was given via the command @@ -981,67 +1000,113 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { // Handle --trace-symbol. for (auto *Arg : Args.filtered(OPT_trace_symbol)) - Symtab.trace(Arg->getValue()); + Symtab->trace(Arg->getValue()); // Add all files to the symbol table. This will add almost all // symbols that we need to the symbol table. for (InputFile *F : Files) - Symtab.addFile(F); + Symtab->addFile<ELFT>(F); + + // Process -defsym option. + for (auto *Arg : Args.filtered(OPT_defsym)) { + StringRef From; + StringRef To; + std::tie(From, To) = StringRef(Arg->getValue()).split('='); + readDefsym(From, MemoryBufferRef(To, "-defsym")); + } + + // Now that we have every file, we can decide if we will need a + // dynamic symbol table. + // We need one if we were asked to export dynamic symbols or if we are + // producing a shared library. + // We also need one if any shared libraries are used and for pie executables + // (probably because the dynamic linker needs it). + Config->HasDynSymTab = + !SharedFiles.empty() || Config->Pic || Config->ExportDynamic; + + // Some symbols (such as __ehdr_start) are defined lazily only when there + // are undefined symbols for them, so we add these to trigger that logic. + for (StringRef Sym : Script->ReferencedSymbols) + Symtab->addUndefined<ELFT>(Sym); + + // Handle the `--undefined <sym>` options. + for (StringRef S : Config->Undefined) + Symtab->fetchIfLazy<ELFT>(S); // If an entry symbol is in a static archive, pull out that file now // to complete the symbol table. After this, no new names except a // few linker-synthesized ones will be added to the symbol table. - if (Symtab.find(Config->Entry)) - Symtab.addUndefined(Config->Entry); + Symtab->fetchIfLazy<ELFT>(Config->Entry); // Return if there were name resolution errors. - if (ErrorCount) + if (errorCount()) return; - // Handle the `--undefined <sym>` options. - Symtab.scanUndefinedFlags(); - // Handle undefined symbols in DSOs. - Symtab.scanShlibUndefined(); + Symtab->scanShlibUndefined<ELFT>(); // Handle the -exclude-libs option. if (Args.hasArg(OPT_exclude_libs)) - excludeLibs(Args, Files); + excludeLibs<ELFT>(Args, Files); + + // Create ElfHeader early. We need a dummy section in + // addReservedSymbols to mark the created symbols as not absolute. + Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC); + Out::ElfHeader->Size = sizeof(typename ELFT::Ehdr); + + // We need to create some reserved symbols such as _end. Create them. + if (!Config->Relocatable) + addReservedSymbols<ELFT>(); // Apply version scripts. - Symtab.scanVersionScript(); + Symtab->scanVersionScript(); // Create wrapped symbols for -wrap option. for (auto *Arg : Args.filtered(OPT_wrap)) - Symtab.addSymbolWrap(Arg->getValue()); - - // Create alias symbols for -defsym option. - for (std::pair<StringRef, StringRef> &Def : getDefsym(Args)) - Symtab.addSymbolAlias(Def.first, Def.second); + Symtab->addSymbolWrap<ELFT>(Arg->getValue()); - Symtab.addCombinedLTOObject(); - if (ErrorCount) + Symtab->addCombinedLTOObject<ELFT>(); + if (errorCount()) return; - // Some symbols (such as __ehdr_start) are defined lazily only when there - // are undefined symbols for them, so we add these to trigger that logic. - for (StringRef Sym : Script->Opt.ReferencedSymbols) - Symtab.addUndefined(Sym); - - // Apply symbol renames for -wrap and -defsym - Symtab.applySymbolRenames(); + // Apply symbol renames for -wrap. + Symtab->applySymbolWrap(); // Now that we have a complete list of input files. // Beyond this point, no new files are added. // Aggregate all input sections into one place. - for (elf::ObjectFile<ELFT> *F : Symtab.getObjectFiles()) + for (InputFile *F : ObjectFiles) for (InputSectionBase *S : F->getSections()) if (S && S != &InputSection::Discarded) InputSections.push_back(S); - for (BinaryFile *F : Symtab.getBinaryFiles()) + for (BinaryFile *F : BinaryFiles) for (InputSectionBase *S : F->getSections()) InputSections.push_back(cast<InputSection>(S)); + // We do not want to emit debug sections if --strip-all + // or -strip-debug are given. + if (Config->Strip != StripPolicy::None) + llvm::erase_if(InputSections, [](InputSectionBase *S) { + return S->Name.startswith(".debug") || S->Name.startswith(".zdebug"); + }); + + Config->EFlags = Target->calcEFlags(); + + if (Config->EMachine == EM_ARM) { + // FIXME: These warnings can be removed when lld only uses these features + // when the input objects have been compiled with an architecture that + // supports them. + if (Config->ARMHasBlx == false) + warn("lld uses blx instruction, no object with architecture supporting " + "feature detected."); + if (Config->ARMJ1J2BranchEncoding == false) + warn("lld uses extended branch encoding, no object with architecture " + "supporting feature detected."); + if (Config->ARMHasMovtMovw == false) + warn("lld may use movt/movw, no object with architecture supporting " + "feature detected."); + } + // This adds a .comment section containing a version string. We have to add it // before decompressAndMergeSections because the .comment section is a // mergeable section. @@ -1050,9 +1115,9 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { // Do size optimizations: garbage collection, merging of SHF_MERGE sections // and identical code folding. - if (Config->GcSections) - markLive<ELFT>(); - decompressAndMergeSections(); + markLive<ELFT>(); + decompressSections(); + mergeSections(); if (Config->ICF) doIcf<ELFT>(); diff --git a/ELF/Driver.h b/ELF/Driver.h index 076dda7730ac..351d7926de71 100644 --- a/ELF/Driver.h +++ b/ELF/Driver.h @@ -11,8 +11,8 @@ #define LLD_ELF_DRIVER_H #include "SymbolTable.h" -#include "lld/Core/LLVM.h" -#include "lld/Core/Reproduce.h" +#include "lld/Common/LLVM.h" +#include "lld/Common/Reproduce.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" @@ -67,6 +67,7 @@ void printHelp(const char *Argv0); std::string createResponseFile(const llvm::opt::InputArgList &Args); llvm::Optional<std::string> findFromSearchPaths(StringRef Path); +llvm::Optional<std::string> searchLinkerScript(StringRef Path); llvm::Optional<std::string> searchLibrary(StringRef Path); } // namespace elf diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp index 5adb09176a3a..2f7c9228851a 100644 --- a/ELF/DriverUtils.cpp +++ b/ELF/DriverUtils.cpp @@ -14,10 +14,10 @@ //===----------------------------------------------------------------------===// #include "Driver.h" -#include "Error.h" -#include "Memory.h" -#include "lld/Config/Version.h" -#include "lld/Core/Reproduce.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" +#include "lld/Common/Reproduce.h" +#include "lld/Common/Version.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" @@ -51,25 +51,26 @@ static const opt::OptTable::Info OptInfo[] = { ELFOptTable::ELFOptTable() : OptTable(OptInfo) {} -// Parse -color-diagnostics={auto,always,never} or -no-color-diagnostics. -static bool getColorDiagnostics(opt::InputArgList &Args) { +// Set color diagnostics according to -color-diagnostics={auto,always,never} +// or -no-color-diagnostics flags. +static void handleColorDiagnostics(opt::InputArgList &Args) { auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, OPT_no_color_diagnostics); if (!Arg) - return ErrorOS->has_colors(); - if (Arg->getOption().getID() == OPT_color_diagnostics) - return true; - if (Arg->getOption().getID() == OPT_no_color_diagnostics) - return false; - - StringRef S = Arg->getValue(); - if (S == "auto") - return ErrorOS->has_colors(); - if (S == "always") - return true; - if (S != "never") - error("unknown option: -color-diagnostics=" + S); - return false; + return; + else if (Arg->getOption().getID() == OPT_color_diagnostics) + errorHandler().ColorDiagnostics = true; + else if (Arg->getOption().getID() == OPT_no_color_diagnostics) + errorHandler().ColorDiagnostics = false; + else { + StringRef S = Arg->getValue(); + if (S == "always") + errorHandler().ColorDiagnostics = true; + else if (S == "never") + errorHandler().ColorDiagnostics = false; + else if (S != "auto") + error("unknown option: -color-diagnostics=" + S); + } } static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { @@ -103,9 +104,7 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) { cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec); Args = this->ParseArgs(Vec, MissingIndex, MissingCount); - // Interpret -color-diagnostics early so that error messages - // for unknown flags are colored. - Config->ColorDiagnostics = getColorDiagnostics(Args); + handleColorDiagnostics(Args); if (MissingCount) error(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); @@ -115,8 +114,8 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) { } void elf::printHelp(const char *Argv0) { - ELFOptTable Table; - Table.PrintHelp(outs(), Argv0, "lld", false); + ELFOptTable().PrintHelp(outs(), Argv0, "lld", false /*ShowHidden*/, + true /*ShowAllAliases*/); outs() << "\n"; // Scripts generated by Libtool versions up to at least 2.4.6 (the most @@ -138,10 +137,11 @@ void elf::printHelp(const char *Argv0) { std::string elf::createResponseFile(const opt::InputArgList &Args) { SmallString<0> Data; raw_svector_ostream OS(Data); + OS << "--chroot .\n"; // Copy the command line to the output while rewriting paths. for (auto *Arg : Args) { - switch (Arg->getOption().getID()) { + switch (Arg->getOption().getUnaliasedOption().getID()) { case OPT_reproduce: break; case OPT_INPUT: @@ -154,17 +154,18 @@ std::string elf::createResponseFile(const opt::InputArgList &Args) { // Strip directories to prevent the issue. OS << "-o " << quote(sys::path::filename(Arg->getValue())) << "\n"; break; - case OPT_L: case OPT_dynamic_list: + case OPT_library_path: case OPT_rpath: - case OPT_alias_script_T: case OPT_script: + case OPT_symbol_ordering_file: + case OPT_sysroot: case OPT_version_script: OS << Arg->getSpelling() << " " << quote(rewritePath(Arg->getValue())) << "\n"; break; default: - OS << toString(Arg) << "\n"; + OS << toString(*Arg) << "\n"; } } return Data.str(); @@ -206,3 +207,12 @@ Optional<std::string> elf::searchLibrary(StringRef Name) { } return None; } + +// If a linker script doesn't exist in the current directory, we also look for +// the script in the '-L' search paths. This matches the behaviour of both '-T' +// and linker script INPUT() directives in ld.bfd. +Optional<std::string> elf::searchLinkerScript(StringRef Name) { + if (fs::exists(Name)) + return Name.str(); + return findFromSearchPaths(Name); +} diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp index c4e3f65c730e..62abc3973e7e 100644 --- a/ELF/EhFrame.cpp +++ b/ELF/EhFrame.cpp @@ -17,11 +17,12 @@ //===----------------------------------------------------------------------===// #include "EhFrame.h" -#include "Error.h" +#include "Config.h" #include "InputSection.h" #include "Relocations.h" #include "Strings.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" @@ -36,7 +37,7 @@ using namespace lld; using namespace lld::elf; namespace { -template <class ELFT> class EhReader { +class EhReader { public: EhReader(InputSectionBase *S, ArrayRef<uint8_t> D) : IS(S), D(D) {} size_t readEhRecordSize(); @@ -45,7 +46,7 @@ public: private: template <class P> void failOn(const P *Loc, const Twine &Msg) { fatal("corrupted .eh_frame: " + Msg + "\n>>> defined in " + - IS->getObjMsg<ELFT>((const uint8_t *)Loc - IS->Data.data())); + IS->getObjMsg((const uint8_t *)Loc - IS->Data.data())); } uint8_t readByte(); @@ -59,22 +60,20 @@ private: }; } -template <class ELFT> size_t elf::readEhRecordSize(InputSectionBase *S, size_t Off) { - return EhReader<ELFT>(S, S->Data.slice(Off)).readEhRecordSize(); + return EhReader(S, S->Data.slice(Off)).readEhRecordSize(); } // .eh_frame section is a sequence of records. Each record starts with // a 4 byte length field. This function reads the length. -template <class ELFT> size_t EhReader<ELFT>::readEhRecordSize() { - const endianness E = ELFT::TargetEndianness; +size_t EhReader::readEhRecordSize() { if (D.size() < 4) failOn(D.data(), "CIE/FDE too small"); // First 4 bytes of CIE/FDE is the size of the record. // If it is 0xFFFFFFFF, the next 8 bytes contain the size instead, // but we do not support that format yet. - uint64_t V = read32<E>(D.data()); + uint64_t V = read32(D.data(), Config->Endianness); if (V == UINT32_MAX) failOn(D.data(), "CIE/FDE too large"); uint64_t Size = V + 4; @@ -84,7 +83,7 @@ template <class ELFT> size_t EhReader<ELFT>::readEhRecordSize() { } // Read a byte and advance D by one byte. -template <class ELFT> uint8_t EhReader<ELFT>::readByte() { +uint8_t EhReader::readByte() { if (D.empty()) failOn(D.data(), "unexpected end of CIE"); uint8_t B = D.front(); @@ -92,14 +91,14 @@ template <class ELFT> uint8_t EhReader<ELFT>::readByte() { return B; } -template <class ELFT> void EhReader<ELFT>::skipBytes(size_t Count) { +void EhReader::skipBytes(size_t Count) { if (D.size() < Count) failOn(D.data(), "CIE is too small"); D = D.slice(Count); } // Read a null-terminated string. -template <class ELFT> StringRef EhReader<ELFT>::readString() { +StringRef EhReader::readString() { const uint8_t *End = std::find(D.begin(), D.end(), '\0'); if (End == D.end()) failOn(D.data(), "corrupted CIE (failed to read string)"); @@ -112,7 +111,7 @@ template <class ELFT> StringRef EhReader<ELFT>::readString() { // Actual number is not of interest because only the runtime needs it. // But we need to be at least able to skip it so that we can read // the field that follows a LEB128 number. -template <class ELFT> void EhReader<ELFT>::skipLeb128() { +void EhReader::skipLeb128() { const uint8_t *ErrPos = D.data(); while (!D.empty()) { uint8_t Val = D.front(); @@ -141,7 +140,7 @@ static size_t getAugPSize(unsigned Enc) { return 0; } -template <class ELFT> void EhReader<ELFT>::skipAugP() { +void EhReader::skipAugP() { uint8_t Enc = readByte(); if ((Enc & 0xf0) == DW_EH_PE_aligned) failOn(D.data() - 1, "DW_EH_PE_aligned encoding is not supported"); @@ -153,12 +152,11 @@ template <class ELFT> void EhReader<ELFT>::skipAugP() { D = D.slice(Size); } -template <class ELFT> uint8_t elf::getFdeEncoding(EhSectionPiece *P) { - auto *IS = static_cast<InputSectionBase *>(P->ID); - return EhReader<ELFT>(IS, P->data()).getFdeEncoding(); +uint8_t elf::getFdeEncoding(EhSectionPiece *P) { + return EhReader(P->Sec, P->data()).getFdeEncoding(); } -template <class ELFT> uint8_t EhReader<ELFT>::getFdeEncoding() { +uint8_t EhReader::getFdeEncoding() { skipBytes(8); int Version = readByte(); if (Version != 1 && Version != 3) @@ -200,13 +198,3 @@ template <class ELFT> uint8_t EhReader<ELFT>::getFdeEncoding() { } return DW_EH_PE_absptr; } - -template size_t elf::readEhRecordSize<ELF32LE>(InputSectionBase *S, size_t Off); -template size_t elf::readEhRecordSize<ELF32BE>(InputSectionBase *S, size_t Off); -template size_t elf::readEhRecordSize<ELF64LE>(InputSectionBase *S, size_t Off); -template size_t elf::readEhRecordSize<ELF64BE>(InputSectionBase *S, size_t Off); - -template uint8_t elf::getFdeEncoding<ELF32LE>(EhSectionPiece *P); -template uint8_t elf::getFdeEncoding<ELF32BE>(EhSectionPiece *P); -template uint8_t elf::getFdeEncoding<ELF64LE>(EhSectionPiece *P); -template uint8_t elf::getFdeEncoding<ELF64BE>(EhSectionPiece *P); diff --git a/ELF/EhFrame.h b/ELF/EhFrame.h index 07d1aaa3cbb3..5112891a911e 100644 --- a/ELF/EhFrame.h +++ b/ELF/EhFrame.h @@ -10,15 +10,15 @@ #ifndef LLD_ELF_EHFRAME_H #define LLD_ELF_EHFRAME_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" namespace lld { namespace elf { class InputSectionBase; struct EhSectionPiece; -template <class ELFT> size_t readEhRecordSize(InputSectionBase *S, size_t Off); -template <class ELFT> uint8_t getFdeEncoding(EhSectionPiece *P); +size_t readEhRecordSize(InputSectionBase *S, size_t Off); +uint8_t getFdeEncoding(EhSectionPiece *P); } // namespace elf } // namespace lld diff --git a/ELF/Error.cpp b/ELF/Error.cpp deleted file mode 100644 index 224570ea7424..000000000000 --- a/ELF/Error.cpp +++ /dev/null @@ -1,116 +0,0 @@ -//===- Error.cpp ----------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Error.h" -#include "Config.h" - -#include "llvm/ADT/Twine.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/raw_ostream.h" -#include <mutex> - -#if !defined(_MSC_VER) && !defined(__MINGW32__) -#include <unistd.h> -#endif - -using namespace llvm; - -using namespace lld; -using namespace lld::elf; - -uint64_t elf::ErrorCount; -raw_ostream *elf::ErrorOS; - -// The functions defined in this file can be called from multiple threads, -// but outs() or errs() are not thread-safe. We protect them using a mutex. -static std::mutex Mu; - -// Prints "\n" or does nothing, depending on Msg contents of -// the previous call of this function. -static void newline(const Twine &Msg) { - // True if the previous error message contained "\n". - // We want to separate multi-line error messages with a newline. - static bool Flag; - - if (Flag) - *ErrorOS << "\n"; - Flag = (StringRef(Msg.str()).find('\n') != StringRef::npos); -} - -static void print(StringRef S, raw_ostream::Colors C) { - *ErrorOS << Config->Argv[0] << ": "; - if (Config->ColorDiagnostics) { - ErrorOS->changeColor(C, true); - *ErrorOS << S; - ErrorOS->resetColor(); - } else { - *ErrorOS << S; - } -} - -void elf::log(const Twine &Msg) { - if (Config->Verbose) { - std::lock_guard<std::mutex> Lock(Mu); - outs() << Config->Argv[0] << ": " << Msg << "\n"; - outs().flush(); - } -} - -void elf::message(const Twine &Msg) { - std::lock_guard<std::mutex> Lock(Mu); - outs() << Msg << "\n"; - outs().flush(); -} - -void elf::warn(const Twine &Msg) { - if (Config->FatalWarnings) { - error(Msg); - return; - } - - std::lock_guard<std::mutex> Lock(Mu); - newline(Msg); - print("warning: ", raw_ostream::MAGENTA); - *ErrorOS << Msg << "\n"; -} - -void elf::error(const Twine &Msg) { - std::lock_guard<std::mutex> Lock(Mu); - newline(Msg); - - if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) { - print("error: ", raw_ostream::RED); - *ErrorOS << Msg << "\n"; - } else if (ErrorCount == Config->ErrorLimit) { - print("error: ", raw_ostream::RED); - *ErrorOS << "too many errors emitted, stopping now" - << " (use -error-limit=0 to see all errors)\n"; - if (Config->ExitEarly) - exitLld(1); - } - - ++ErrorCount; -} - -void elf::exitLld(int Val) { - // Dealloc/destroy ManagedStatic variables before calling - // _exit(). In a non-LTO build, this is a nop. In an LTO - // build allows us to get the output of -time-passes. - llvm_shutdown(); - - outs().flush(); - errs().flush(); - _exit(Val); -} - -void elf::fatal(const Twine &Msg) { - error(Msg); - exitLld(1); -} diff --git a/ELF/Error.h b/ELF/Error.h deleted file mode 100644 index 89bc2111b44e..000000000000 --- a/ELF/Error.h +++ /dev/null @@ -1,78 +0,0 @@ -//===- Error.h --------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// In LLD, we have three levels of errors: fatal, error or warn. -// -// Fatal makes the program exit immediately with an error message. -// You shouldn't use it except for reporting a corrupted input file. -// -// Error prints out an error message and increment a global variable -// ErrorCount to record the fact that we met an error condition. It does -// not exit, so it is safe for a lld-as-a-library use case. It is generally -// useful because it can report more than one error in a single run. -// -// Warn doesn't do anything but printing out a given message. -// -// It is not recommended to use llvm::outs() or llvm::errs() directly -// in LLD because they are not thread-safe. The functions declared in -// this file are mutually excluded, so you want to use them instead. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_ELF_ERROR_H -#define LLD_ELF_ERROR_H - -#include "lld/Core/LLVM.h" - -#include "llvm/Support/Error.h" - -namespace lld { -namespace elf { - -extern uint64_t ErrorCount; -extern llvm::raw_ostream *ErrorOS; - -void log(const Twine &Msg); -void message(const Twine &Msg); -void warn(const Twine &Msg); -void error(const Twine &Msg); -LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); - -LLVM_ATTRIBUTE_NORETURN void exitLld(int Val); - -// check() functions are convenient functions to strip errors -// from error-or-value objects. -template <class T> T check(ErrorOr<T> E) { - if (auto EC = E.getError()) - fatal(EC.message()); - return std::move(*E); -} - -template <class T> T check(Expected<T> E) { - if (!E) - fatal(llvm::toString(E.takeError())); - return std::move(*E); -} - -template <class T> T check(ErrorOr<T> E, const Twine &Prefix) { - if (auto EC = E.getError()) - fatal(Prefix + ": " + EC.message()); - return std::move(*E); -} - -template <class T> T check(Expected<T> E, const Twine &Prefix) { - if (!E) - fatal(Prefix + ": " + toString(E.takeError())); - return std::move(*E); -} - -} // namespace elf -} // namespace lld - -#endif diff --git a/ELF/Filesystem.cpp b/ELF/Filesystem.cpp index d468ae0c618a..8d0b5d8a2f1c 100644 --- a/ELF/Filesystem.cpp +++ b/ELF/Filesystem.cpp @@ -13,8 +13,13 @@ #include "Filesystem.h" #include "Config.h" -#include "llvm/Support/FileSystem.h" +#include "lld/Common/Threads.h" +#include "llvm/Config/llvm-config.h" #include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/FileSystem.h" +#if LLVM_ON_UNIX +#include <unistd.h> +#endif #include <thread> using namespace llvm; @@ -35,27 +40,29 @@ using namespace lld::elf; // Since LLD can link a 1 GB binary in about 5 seconds, that waste // actually counts. // -// This function spawns a background thread to call unlink. +// This function spawns a background thread to remove the file. // The calling thread returns almost immediately. void elf::unlinkAsync(StringRef Path) { - if (!Config->Threads || !sys::fs::exists(Config->OutputFile) || - !sys::fs::is_regular_file(Config->OutputFile)) +// Removing a file is async on windows. +#if defined(LLVM_ON_WIN32) + sys::fs::remove(Path); +#else + if (!ThreadsEnabled || !sys::fs::exists(Path) || + !sys::fs::is_regular_file(Path)) return; - // First, rename Path to avoid race condition. We cannot remove - // Path from a different thread because we are now going to create - // Path as a new file. If we do that in a different thread, the new - // thread can remove the new file. - SmallString<128> TempPath; - if (sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath)) - return; - if (sys::fs::rename(Path, TempPath)) { - sys::fs::remove(TempPath); - return; - } + // We cannot just remove path from a different thread because we are now going + // to create path as a new file. + // Instead we open the file and unlink it on this thread. The unlink is fast + // since the open fd guarantees that it is not removing the last reference. + int FD; + std::error_code EC = sys::fs::openFileForRead(Path, FD); + sys::fs::remove(Path); - // Remove TempPath in background. - std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach(); + // close and therefore remove TempPath in background. + if (!EC) + std::thread([=] { ::close(FD); }).detach(); +#endif } // Simulate file creation to see if Path is writable. @@ -73,5 +80,7 @@ void elf::unlinkAsync(StringRef Path) { std::error_code elf::tryCreateFile(StringRef Path) { if (Path.empty()) return std::error_code(); - return FileOutputBuffer::create(Path, 1).getError(); + if (Path == "-") + return std::error_code(); + return errorToErrorCode(FileOutputBuffer::create(Path, 1).takeError()); } diff --git a/ELF/Filesystem.h b/ELF/Filesystem.h index dbeadac5a96b..987a74a6bcb6 100644 --- a/ELF/Filesystem.h +++ b/ELF/Filesystem.h @@ -10,7 +10,8 @@ #ifndef LLD_ELF_FILESYSTEM_H #define LLD_ELF_FILESYSTEM_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" +#include <system_error> namespace lld { namespace elf { diff --git a/ELF/GdbIndex.cpp b/ELF/GdbIndex.cpp index 99e02d0025b0..d27b57f95938 100644 --- a/ELF/GdbIndex.cpp +++ b/ELF/GdbIndex.cpp @@ -15,7 +15,8 @@ //===----------------------------------------------------------------------===// #include "GdbIndex.h" -#include "Memory.h" +#include "Symbols.h" +#include "lld/Common/Memory.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/Object/ELFObjectFile.h" @@ -24,26 +25,77 @@ using namespace llvm::object; using namespace lld; using namespace lld::elf; -std::pair<bool, GdbSymbol *> GdbHashTab::add(uint32_t Hash, size_t Offset) { - GdbSymbol *&Sym = Map[Offset]; - if (Sym) - return {false, Sym}; - Sym = make<GdbSymbol>(Hash, Offset); - return {true, Sym}; +template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *Obj) { + for (InputSectionBase *Sec : Obj->getSections()) { + if (!Sec) + continue; + if (LLDDWARFSection *M = StringSwitch<LLDDWARFSection *>(Sec->Name) + .Case(".debug_info", &InfoSection) + .Case(".debug_ranges", &RangeSection) + .Case(".debug_line", &LineSection) + .Default(nullptr)) { + Sec->maybeUncompress(); + M->Data = toStringRef(Sec->Data); + M->Sec = Sec; + continue; + } + if (Sec->Name == ".debug_abbrev") + AbbrevSection = toStringRef(Sec->Data); + else if (Sec->Name == ".debug_gnu_pubnames") + GnuPubNamesSection = toStringRef(Sec->Data); + else if (Sec->Name == ".debug_gnu_pubtypes") + GnuPubTypesSection = toStringRef(Sec->Data); + else if (Sec->Name == ".debug_str") + StrSection = toStringRef(Sec->Data); + } } -void GdbHashTab::finalizeContents() { - uint32_t Size = std::max<uint32_t>(1024, NextPowerOf2(Map.size() * 4 / 3)); - uint32_t Mask = Size - 1; - Table.resize(Size); +// Find if there is a relocation at Pos in Sec. The code is a bit +// more complicated than usual because we need to pass a section index +// to llvm since it has no idea about InputSection. +template <class ELFT> +template <class RelTy> +Optional<RelocAddrEntry> +LLDDwarfObj<ELFT>::findAux(const InputSectionBase &Sec, uint64_t Pos, + ArrayRef<RelTy> Rels) const { + auto It = std::lower_bound( + Rels.begin(), Rels.end(), Pos, + [](const RelTy &A, uint64_t B) { return A.r_offset < B; }); + if (It == Rels.end() || It->r_offset != Pos) + return None; + const RelTy &Rel = *It; - for (auto &P : Map) { - GdbSymbol *Sym = P.second; - uint32_t I = Sym->NameHash & Mask; - uint32_t Step = ((Sym->NameHash * 17) & Mask) | 1; + const ObjFile<ELFT> *File = Sec.getFile<ELFT>(); + uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); + const typename ELFT::Sym &Sym = File->getELFSyms()[SymIndex]; + uint32_t SecIndex = File->getSectionIndex(Sym); - while (Table[I]) - I = (I + Step) & Mask; - Table[I] = Sym; + // Broken debug info can point to a non-Defined symbol. + auto *DR = dyn_cast<Defined>(&File->getRelocTargetSym(Rel)); + if (!DR) { + error("unsupported relocation target while parsing debug info"); + return None; } + uint64_t Val = DR->Value + getAddend<ELFT>(Rel); + + // FIXME: We should be consistent about always adding the file + // offset or not. + if (DR->Section->Flags & ELF::SHF_ALLOC) + Val += cast<InputSection>(DR->Section)->getOffsetInFile(); + + return RelocAddrEntry{SecIndex, Val}; } + +template <class ELFT> +Optional<RelocAddrEntry> LLDDwarfObj<ELFT>::find(const llvm::DWARFSection &S, + uint64_t Pos) const { + auto &Sec = static_cast<const LLDDWARFSection &>(S); + if (Sec.Sec->AreRelocsRela) + return findAux(*Sec.Sec, Pos, Sec.Sec->template relas<ELFT>()); + return findAux(*Sec.Sec, Pos, Sec.Sec->template rels<ELFT>()); +} + +template class elf::LLDDwarfObj<ELF32LE>; +template class elf::LLDDwarfObj<ELF32BE>; +template class elf::LLDDwarfObj<ELF64LE>; +template class elf::LLDDwarfObj<ELF64BE>; diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h index bc024e6689ef..41ae9d793c11 100644 --- a/ELF/GdbIndex.h +++ b/ELF/GdbIndex.h @@ -19,61 +19,50 @@ namespace elf { class InputSection; -// Struct represents single entry of address area of gdb index. -struct AddressEntry { - InputSection *Section; - uint64_t LowAddress; - uint64_t HighAddress; - uint32_t CuIndex; +struct LLDDWARFSection final : public llvm::DWARFSection { + InputSectionBase *Sec = nullptr; }; -// Struct represents single entry of compilation units list area of gdb index. -// It consist of CU offset in .debug_info section and it's size. -struct CompilationUnitEntry { - uint64_t CuOffset; - uint64_t CuLength; -}; - -// Represents data about symbol and type names which are used -// to build symbol table and constant pool area of gdb index. -struct NameTypeEntry { - StringRef Name; - uint8_t Type; -}; - -// We fill one GdbIndexDataChunk for each object where scan of -// debug information performed. That information futher used -// for filling gdb index section areas. -struct GdbIndexChunk { - InputSection *DebugInfoSec; - std::vector<AddressEntry> AddressArea; - std::vector<CompilationUnitEntry> CompilationUnits; - std::vector<NameTypeEntry> NamesAndTypes; -}; +template <class ELFT> class LLDDwarfObj final : public llvm::DWARFObject { + LLDDWARFSection InfoSection; + LLDDWARFSection RangeSection; + LLDDWARFSection LineSection; + StringRef AbbrevSection; + StringRef GnuPubNamesSection; + StringRef GnuPubTypesSection; + StringRef StrSection; -// Element of GdbHashTab hash table. -struct GdbSymbol { - GdbSymbol(uint32_t Hash, size_t Offset) - : NameHash(Hash), NameOffset(Offset) {} - uint32_t NameHash; - size_t NameOffset; - size_t CuVectorIndex; -}; + template <class RelTy> + llvm::Optional<llvm::RelocAddrEntry> findAux(const InputSectionBase &Sec, + uint64_t Pos, + ArrayRef<RelTy> Rels) const; -// This class manages the hashed symbol table for the .gdb_index section. -// The hash value for a table entry is computed by applying an iterative hash -// function to the symbol's name. -class GdbHashTab final { public: - std::pair<bool, GdbSymbol *> add(uint32_t Hash, size_t Offset); - - void finalizeContents(); - size_t getCapacity() { return Table.size(); } - GdbSymbol *getSymbol(size_t I) { return Table[I]; } - -private: - llvm::DenseMap<size_t, GdbSymbol *> Map; - std::vector<GdbSymbol *> Table; + explicit LLDDwarfObj(ObjFile<ELFT> *Obj); + const llvm::DWARFSection &getInfoSection() const override { + return InfoSection; + } + const llvm::DWARFSection &getRangeSection() const override { + return RangeSection; + } + const llvm::DWARFSection &getLineSection() const override { + return LineSection; + } + StringRef getFileName() const override { return ""; } + StringRef getCUIndexSection() const override { return ""; } + StringRef getAbbrevSection() const override { return AbbrevSection; } + StringRef getStringSection() const override { return StrSection; } + StringRef getGnuPubNamesSection() const override { + return GnuPubNamesSection; + } + StringRef getGnuPubTypesSection() const override { + return GnuPubTypesSection; + } + bool isLittleEndian() const override { + return ELFT::TargetEndianness == llvm::support::little; + } + llvm::Optional<llvm::RelocAddrEntry> find(const llvm::DWARFSection &Sec, + uint64_t Pos) const override; }; } // namespace elf diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp index 09512a8b09d9..b1e12e0590d5 100644 --- a/ELF/ICF.cpp +++ b/ELF/ICF.cpp @@ -76,7 +76,8 @@ #include "ICF.h" #include "Config.h" #include "SymbolTable.h" -#include "Threads.h" +#include "Symbols.h" +#include "lld/Common/Threads.h" #include "llvm/ADT/Hashing.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" @@ -155,16 +156,20 @@ private: // Returns a hash value for S. Note that the information about // relocation targets is not included in the hash value. template <class ELFT> static uint32_t getHash(InputSection *S) { - return hash_combine(S->Flags, S->getSize(), S->NumRelocations); + return hash_combine(S->Flags, S->getSize(), S->NumRelocations, S->Data); } // Returns true if section S is subject of ICF. static bool isEligible(InputSection *S) { + // Don't merge read only data sections unless --icf-data was passed. + if (!(S->Flags & SHF_EXECINSTR) && !Config->ICFData) + return false; + // .init and .fini contains instructions that must be executed to // initialize and finalize the process. They cannot and should not // be merged. - return S->Live && (S->Flags & SHF_ALLOC) && (S->Flags & SHF_EXECINSTR) && - !(S->Flags & SHF_WRITE) && S->Name != ".init" && S->Name != ".fini"; + return S->Live && (S->Flags & SHF_ALLOC) && !(S->Flags & SHF_WRITE) && + S->Name != ".init" && S->Name != ".fini"; } // Split an equivalence class into smaller classes. @@ -207,38 +212,49 @@ void ICF<ELFT>::segregate(size_t Begin, size_t End, bool Constant) { // Compare two lists of relocations. template <class ELFT> template <class RelTy> -bool ICF<ELFT>::constantEq(const InputSection *A, ArrayRef<RelTy> RelsA, - const InputSection *B, ArrayRef<RelTy> RelsB) { - auto Eq = [&](const RelTy &RA, const RelTy &RB) { - if (RA.r_offset != RB.r_offset || - RA.getType(Config->IsMips64EL) != RB.getType(Config->IsMips64EL)) +bool ICF<ELFT>::constantEq(const InputSection *SecA, ArrayRef<RelTy> RA, + const InputSection *SecB, ArrayRef<RelTy> RB) { + if (RA.size() != RB.size()) + return false; + + for (size_t I = 0; I < RA.size(); ++I) { + if (RA[I].r_offset != RB[I].r_offset || + RA[I].getType(Config->IsMips64EL) != RB[I].getType(Config->IsMips64EL)) return false; - uint64_t AddA = getAddend<ELFT>(RA); - uint64_t AddB = getAddend<ELFT>(RB); - SymbolBody &SA = A->template getFile<ELFT>()->getRelocTargetSym(RA); - SymbolBody &SB = B->template getFile<ELFT>()->getRelocTargetSym(RB); - if (&SA == &SB) - return AddA == AddB; + uint64_t AddA = getAddend<ELFT>(RA[I]); + uint64_t AddB = getAddend<ELFT>(RB[I]); - auto *DA = dyn_cast<DefinedRegular>(&SA); - auto *DB = dyn_cast<DefinedRegular>(&SB); + Symbol &SA = SecA->template getFile<ELFT>()->getRelocTargetSym(RA[I]); + Symbol &SB = SecB->template getFile<ELFT>()->getRelocTargetSym(RB[I]); + if (&SA == &SB) { + if (AddA == AddB) + continue; + return false; + } + + auto *DA = dyn_cast<Defined>(&SA); + auto *DB = dyn_cast<Defined>(&SB); if (!DA || !DB) return false; // Relocations referring to absolute symbols are constant-equal if their // values are equal. + if (!DA->Section && !DB->Section && DA->Value + AddA == DB->Value + AddB) + continue; if (!DA->Section || !DB->Section) - return !DA->Section && !DB->Section && - DA->Value + AddA == DB->Value + AddB; + return false; if (DA->Section->kind() != DB->Section->kind()) return false; // Relocations referring to InputSections are constant-equal if their // section offsets are equal. - if (isa<InputSection>(DA->Section)) - return DA->Value + AddA == DB->Value + AddB; + if (isa<InputSection>(DA->Section)) { + if (DA->Value + AddA == DB->Value + AddB) + continue; + return false; + } // Relocations referring to MergeInputSections are constant-equal if their // offsets in the output section are equal. @@ -253,11 +269,11 @@ bool ICF<ELFT>::constantEq(const InputSection *A, ArrayRef<RelTy> RelsA, SA.isSection() ? X->getOffset(AddA) : X->getOffset(DA->Value) + AddA; uint64_t OffsetB = SB.isSection() ? Y->getOffset(AddB) : Y->getOffset(DB->Value) + AddB; - return OffsetA == OffsetB; - }; + if (OffsetA != OffsetB) + return false; + } - return RelsA.size() == RelsB.size() && - std::equal(RelsA.begin(), RelsA.end(), RelsB.begin(), Eq); + return true; } // Compare "non-moving" part of two InputSections, namely everything @@ -278,37 +294,39 @@ bool ICF<ELFT>::equalsConstant(const InputSection *A, const InputSection *B) { // relocations point to the same section in terms of ICF. template <class ELFT> template <class RelTy> -bool ICF<ELFT>::variableEq(const InputSection *A, ArrayRef<RelTy> RelsA, - const InputSection *B, ArrayRef<RelTy> RelsB) { - auto Eq = [&](const RelTy &RA, const RelTy &RB) { +bool ICF<ELFT>::variableEq(const InputSection *SecA, ArrayRef<RelTy> RA, + const InputSection *SecB, ArrayRef<RelTy> RB) { + assert(RA.size() == RB.size()); + + for (size_t I = 0; I < RA.size(); ++I) { // The two sections must be identical. - SymbolBody &SA = A->template getFile<ELFT>()->getRelocTargetSym(RA); - SymbolBody &SB = B->template getFile<ELFT>()->getRelocTargetSym(RB); + Symbol &SA = SecA->template getFile<ELFT>()->getRelocTargetSym(RA[I]); + Symbol &SB = SecB->template getFile<ELFT>()->getRelocTargetSym(RB[I]); if (&SA == &SB) - return true; + continue; - auto *DA = cast<DefinedRegular>(&SA); - auto *DB = cast<DefinedRegular>(&SB); + auto *DA = cast<Defined>(&SA); + auto *DB = cast<Defined>(&SB); // We already dealt with absolute and non-InputSection symbols in // constantEq, and for InputSections we have already checked everything // except the equivalence class. if (!DA->Section) - return true; + continue; auto *X = dyn_cast<InputSection>(DA->Section); if (!X) - return true; + continue; auto *Y = cast<InputSection>(DB->Section); // Ineligible sections are in the special equivalence class 0. // They can never be the same in terms of the equivalence class. if (X->Class[Current] == 0) return false; - - return X->Class[Current] == Y->Class[Current]; + if (X->Class[Current] != Y->Class[Current]) + return false; }; - return std::equal(RelsA.begin(), RelsA.end(), RelsB.begin(), Eq); + return true; } // Compare "moving" part of two InputSections, namely relocation targets. @@ -353,7 +371,7 @@ template <class ELFT> void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) { // If threading is disabled or the number of sections are // too small to use threading, call Fn sequentially. - if (!Config->Threads || Sections.size() < 1024) { + if (!ThreadsEnabled || Sections.size() < 1024) { forEachClassRange(0, Sections.size(), Fn); ++Cnt; return; @@ -381,9 +399,10 @@ template <class ELFT> void ICF<ELFT>::run() { Sections.push_back(S); // Initially, we use hash values to partition sections. - for (InputSection *S : Sections) + parallelForEach(Sections, [&](InputSection *S) { // Set MSB to 1 to avoid collisions with non-hash IDs. S->Class[0] = getHash<ELFT>(S) | (1 << 31); + }); // From now on, sections in Sections vector are ordered so that sections // in the same equivalence class are consecutive in the vector. diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index c609615fcc2e..1f68340c9428 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -8,13 +8,13 @@ //===----------------------------------------------------------------------===// #include "InputFiles.h" -#include "Error.h" #include "InputSection.h" #include "LinkerScript.h" -#include "Memory.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" @@ -23,6 +23,8 @@ #include "llvm/LTO/LTO.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/ARMAttributeParser.h" +#include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/raw_ostream.h" @@ -35,26 +37,23 @@ using namespace llvm::sys::fs; using namespace lld; using namespace lld::elf; +std::vector<BinaryFile *> elf::BinaryFiles; +std::vector<BitcodeFile *> elf::BitcodeFiles; +std::vector<InputFile *> elf::ObjectFiles; +std::vector<InputFile *> elf::SharedFiles; + TarWriter *elf::Tar; InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} -namespace { -// In ELF object file all section addresses are zero. If we have multiple -// .text sections (when using -ffunction-section or comdat group) then -// LLVM DWARF parser will not be able to parse .debug_line correctly, unless -// we assign each section some unique address. This callback method assigns -// each section an address equal to its offset in ELF object file. -class ObjectInfo : public LoadedObjectInfoHelper<ObjectInfo> { -public: - uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override { - return static_cast<const ELFSectionRef &>(Sec).getOffset(); - } -}; -} - Optional<MemoryBufferRef> elf::readFile(StringRef Path) { + // The --chroot option changes our virtual root directory. + // This is useful when you are dealing with files created by --reproduce. + if (!Config->Chroot.empty() && Path.startswith("/")) + Path = Saver.save(Config->Chroot + Path); + log(Path); + auto MBOrErr = MemoryBuffer::getFile(Path); if (auto EC = MBOrErr.getError()) { error("cannot open " + Path + ": " + EC.message()); @@ -70,28 +69,88 @@ Optional<MemoryBufferRef> elf::readFile(StringRef Path) { return MBRef; } -template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() { - std::unique_ptr<object::ObjectFile> Obj = - check(object::ObjectFile::createObjectFile(this->MB), toString(this)); - - ObjectInfo ObjInfo; - DWARFContextInMemory Dwarf(*Obj, &ObjInfo); +template <class ELFT> void ObjFile<ELFT>::initializeDwarf() { + DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(this)); + const DWARFObject &Obj = Dwarf.getDWARFObj(); DwarfLine.reset(new DWARFDebugLine); - DWARFDataExtractor LineData(Dwarf.getLineSection(), Config->IsLE, + DWARFDataExtractor LineData(Obj, Obj.getLineSection(), Config->IsLE, Config->Wordsize); // The second parameter is offset in .debug_line section // for compilation unit (CU) of interest. We have only one // CU (object file), so offset is always 0. - DwarfLine->getOrParseLineTable(LineData, 0); + // FIXME: Provide the associated DWARFUnit if there is one. DWARF v5 + // needs it in order to find indirect strings. + const DWARFDebugLine::LineTable *LT = + DwarfLine->getOrParseLineTable(LineData, 0, nullptr); + + // Return if there is no debug information about CU available. + if (!Dwarf.getNumCompileUnits()) + return; + + // Loop over variable records and insert them to VariableLoc. + DWARFCompileUnit *CU = Dwarf.getCompileUnitAtIndex(0); + for (const auto &Entry : CU->dies()) { + DWARFDie Die(CU, &Entry); + // Skip all tags that are not variables. + if (Die.getTag() != dwarf::DW_TAG_variable) + continue; + + // Skip if a local variable because we don't need them for generating error + // messages. In general, only non-local symbols can fail to be linked. + if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0)) + continue; + + // Get the source filename index for the variable. + unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0); + if (!LT->hasFileAtIndex(File)) + continue; + + // Get the line number on which the variable is declared. + unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0); + + // Get the name of the variable and add the collected information to + // VariableLoc. Usually Name is non-empty, but it can be empty if the input + // object file lacks some debug info. + StringRef Name = dwarf::toString(Die.find(dwarf::DW_AT_name), ""); + if (!Name.empty()) + VariableLoc.insert({Name, {File, Line}}); + } +} + +// Returns the pair of file name and line number describing location of data +// object (variable, array, etc) definition. +template <class ELFT> +Optional<std::pair<std::string, unsigned>> +ObjFile<ELFT>::getVariableLoc(StringRef Name) { + llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); + + // There is always only one CU so it's offset is 0. + const DWARFDebugLine::LineTable *LT = DwarfLine->getLineTable(0); + if (!LT) + return None; + + // Return if we have no debug information about data object. + auto It = VariableLoc.find(Name); + if (It == VariableLoc.end()) + return None; + + // Take file name string from line table. + std::string FileName; + if (!LT->getFileNameByIndex( + It->second.first /* File */, nullptr, + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName)) + return None; + + return std::make_pair(FileName, It->second.second /*Line*/); } // Returns source line information for a given offset // using DWARF debug info. template <class ELFT> -Optional<DILineInfo> elf::ObjectFile<ELFT>::getDILineInfo(InputSectionBase *S, - uint64_t Offset) { - llvm::call_once(InitDwarfLine, [this]() { initializeDwarfLine(); }); +Optional<DILineInfo> ObjFile<ELFT>::getDILineInfo(InputSectionBase *S, + uint64_t Offset) { + llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); // The offset to CU is 0. const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0); @@ -112,8 +171,7 @@ Optional<DILineInfo> elf::ObjectFile<ELFT>::getDILineInfo(InputSectionBase *S, // Returns source line information for a given offset // using DWARF debug info. template <class ELFT> -std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase *S, - uint64_t Offset) { +std::string ObjFile<ELFT>::getLineInfo(InputSectionBase *S, uint64_t Offset) { if (Optional<DILineInfo> Info = getDILineInfo(S, Offset)) return Info->FileName + ":" + std::to_string(Info->Line); return ""; @@ -145,50 +203,41 @@ ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) { } template <class ELFT> -typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalSymbols() { - return makeArrayRef(Symbols.begin() + FirstNonLocal, Symbols.end()); +typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalELFSyms() { + return makeArrayRef(ELFSyms.begin() + FirstNonLocal, ELFSyms.end()); } template <class ELFT> uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const { - return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX), - toString(this)); + return CHECK(getObj().getSectionIndex(&Sym, ELFSyms, SymtabSHNDX), this); } template <class ELFT> void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections, const Elf_Shdr *Symtab) { FirstNonLocal = Symtab->sh_info; - Symbols = check(getObj().symbols(Symtab), toString(this)); - if (FirstNonLocal == 0 || FirstNonLocal > Symbols.size()) + ELFSyms = CHECK(getObj().symbols(Symtab), this); + if (FirstNonLocal == 0 || FirstNonLocal > ELFSyms.size()) fatal(toString(this) + ": invalid sh_info in symbol table"); - StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections), - toString(this)); + StringTable = + CHECK(getObj().getStringTableForSymtab(*Symtab, Sections), this); } template <class ELFT> -elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M, StringRef ArchiveName) - : ELFFileBase<ELFT>(Base::ObjectKind, M) { +ObjFile<ELFT>::ObjFile(MemoryBufferRef M, StringRef ArchiveName) + : ELFFileBase<ELFT>(Base::ObjKind, M) { this->ArchiveName = ArchiveName; } -template <class ELFT> -ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getLocalSymbols() { - if (this->SymbolBodies.empty()) - return this->SymbolBodies; - return makeArrayRef(this->SymbolBodies).slice(1, this->FirstNonLocal - 1); -} - -template <class ELFT> -ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getSymbols() { - if (this->SymbolBodies.empty()) - return this->SymbolBodies; - return makeArrayRef(this->SymbolBodies).slice(1); +template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getLocalSymbols() { + if (this->Symbols.empty()) + return {}; + return makeArrayRef(this->Symbols).slice(1, this->FirstNonLocal - 1); } template <class ELFT> -void elf::ObjectFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { +void ObjFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { // Read section and symbol tables. initializeSections(ComdatGroups); initializeSymbols(); @@ -198,19 +247,17 @@ void elf::ObjectFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { // They are identified and deduplicated by group name. This function // returns a group name. template <class ELFT> -StringRef -elf::ObjectFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections, - const Elf_Shdr &Sec) { +StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections, + const Elf_Shdr &Sec) { // Group signatures are stored as symbol names in object files. // sh_info contains a symbol index, so we fetch a symbol and read its name. - if (this->Symbols.empty()) + if (this->ELFSyms.empty()) this->initSymtab( - Sections, - check(object::getSection<ELFT>(Sections, Sec.sh_link), toString(this))); + Sections, CHECK(object::getSection<ELFT>(Sections, Sec.sh_link), this)); - const Elf_Sym *Sym = check( - object::getSymbol<ELFT>(this->Symbols, Sec.sh_info), toString(this)); - StringRef Signature = check(Sym->getName(this->StringTable), toString(this)); + const Elf_Sym *Sym = + CHECK(object::getSymbol<ELFT>(this->ELFSyms, Sec.sh_info), this); + StringRef Signature = CHECK(Sym->getName(this->StringTable), this); // As a special case, if a symbol is a section symbol and has no name, // we use a section name as a signature. @@ -225,32 +272,22 @@ elf::ObjectFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections, } template <class ELFT> -ArrayRef<typename elf::ObjectFile<ELFT>::Elf_Word> -elf::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) { +ArrayRef<typename ObjFile<ELFT>::Elf_Word> +ObjFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) { const ELFFile<ELFT> &Obj = this->getObj(); - ArrayRef<Elf_Word> Entries = check( - Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), toString(this)); + ArrayRef<Elf_Word> Entries = + CHECK(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), this); if (Entries.empty() || Entries[0] != GRP_COMDAT) fatal(toString(this) + ": unsupported SHT_GROUP format"); return Entries.slice(1); } -template <class ELFT> -bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { +template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { // We don't merge sections if -O0 (default is -O1). This makes sometimes // the linker significantly faster, although the output will be bigger. if (Config->Optimize == 0) return false; - // Do not merge sections if generating a relocatable object. It makes - // the code simpler because we do not need to update relocation addends - // to reflect changes introduced by merging. Instead of that we write - // such "merge" sections into separate OutputSections and keep SHF_MERGE - // / SHF_STRINGS flags and sh_entsize value to be able to perform merging - // later during a final linking. - if (Config->Relocatable) - return false; - // A mergeable section with size 0 is useless because they don't have // any data to merge. A mergeable string section with size 0 can be // argued as invalid because it doesn't end with a null character. @@ -276,29 +313,19 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { if (Flags & SHF_WRITE) fatal(toString(this) + ": writable SHF_MERGE section is not supported"); - // Don't try to merge if the alignment is larger than the sh_entsize and this - // is not SHF_STRINGS. - // - // Since this is not a SHF_STRINGS, we would need to pad after every entity. - // It would be equivalent for the producer of the .o to just set a larger - // sh_entsize. - if (Flags & SHF_STRINGS) - return true; - - return Sec.sh_addralign <= EntSize; + return true; } template <class ELFT> -void elf::ObjectFile<ELFT>::initializeSections( +void ObjFile<ELFT>::initializeSections( DenseSet<CachedHashStringRef> &ComdatGroups) { const ELFFile<ELFT> &Obj = this->getObj(); - ArrayRef<Elf_Shdr> ObjSections = - check(this->getObj().sections(), toString(this)); + ArrayRef<Elf_Shdr> ObjSections = CHECK(this->getObj().sections(), this); uint64_t Size = ObjSections.size(); this->Sections.resize(Size); this->SectionStringTable = - check(Obj.getSectionStringTable(ObjSections), toString(this)); + CHECK(Obj.getSectionStringTable(ObjSections), this); for (size_t I = 0, E = ObjSections.size(); I < E; I++) { if (this->Sections[I] == &InputSection::Discarded) @@ -344,8 +371,7 @@ void elf::ObjectFile<ELFT>::initializeSections( this->initSymtab(ObjSections, &Sec); break; case SHT_SYMTAB_SHNDX: - this->SymtabSHNDX = - check(Obj.getSHNDXTable(Sec, ObjSections), toString(this)); + this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, ObjSections), this); break; case SHT_STRTAB: case SHT_NULL: @@ -361,13 +387,55 @@ void elf::ObjectFile<ELFT>::initializeSections( fatal(toString(this) + ": invalid sh_link index: " + Twine(Sec.sh_link)); this->Sections[Sec.sh_link]->DependentSections.push_back( - this->Sections[I]); + cast<InputSection>(this->Sections[I])); } } } +// The ARM support in lld makes some use of instructions that are not available +// on all ARM architectures. Namely: +// - Use of BLX instruction for interworking between ARM and Thumb state. +// - Use of the extended Thumb branch encoding in relocation. +// - Use of the MOVT/MOVW instructions in Thumb Thunks. +// The ARM Attributes section contains information about the architecture chosen +// at compile time. We follow the convention that if at least one input object +// is compiled with an architecture that supports these features then lld is +// permitted to use them. +static void updateSupportedARMFeatures(const ARMAttributeParser &Attributes) { + if (!Attributes.hasAttribute(ARMBuildAttrs::CPU_arch)) + return; + auto Arch = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch); + switch (Arch) { + case ARMBuildAttrs::Pre_v4: + case ARMBuildAttrs::v4: + case ARMBuildAttrs::v4T: + // Architectures prior to v5 do not support BLX instruction + break; + case ARMBuildAttrs::v5T: + case ARMBuildAttrs::v5TE: + case ARMBuildAttrs::v5TEJ: + case ARMBuildAttrs::v6: + case ARMBuildAttrs::v6KZ: + case ARMBuildAttrs::v6K: + Config->ARMHasBlx = true; + // Architectures used in pre-Cortex processors do not support + // The J1 = 1 J2 = 1 Thumb branch range extension, with the exception + // of Architecture v6T2 (arm1156t2-s and arm1156t2f-s) that do. + break; + default: + // All other Architectures have BLX and extended branch encoding + Config->ARMHasBlx = true; + Config->ARMJ1J2BranchEncoding = true; + if (Arch != ARMBuildAttrs::v6_M && Arch != ARMBuildAttrs::v6S_M) + // All Architectures used in Cortex processors with the exception + // of v6-M and v6S-M have the MOVT and MOVW instructions. + Config->ARMHasMovtMovw = true; + break; + } +} + template <class ELFT> -InputSectionBase *elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) { +InputSectionBase *ObjFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) { uint32_t Idx = Sec.sh_info; if (Idx >= this->Sections.size()) fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx)); @@ -394,21 +462,26 @@ InputSectionBase *toRegularSection(MergeInputSection *Sec) { } template <class ELFT> -InputSectionBase * -elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { +InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { StringRef Name = getSectionName(Sec); switch (Sec.sh_type) { - case SHT_ARM_ATTRIBUTES: - // FIXME: ARM meta-data section. Retain the first attribute section - // we see. The eglibc ARM dynamic loaders require the presence of an - // attribute section for dlopen to work. - // In a full implementation we would merge all attribute sections. + case SHT_ARM_ATTRIBUTES: { + if (Config->EMachine != EM_ARM) + break; + ARMAttributeParser Attributes; + ArrayRef<uint8_t> Contents = check(this->getObj().getSectionContents(&Sec)); + Attributes.Parse(Contents, /*isLittle*/Config->EKind == ELF32LEKind); + updateSupportedARMFeatures(Attributes); + // FIXME: Retain the first attribute section we see. The eglibc ARM + // dynamic loaders require the presence of an attribute section for dlopen + // to work. In a full implementation we would merge all attribute sections. if (InX::ARMAttributes == nullptr) { InX::ARMAttributes = make<InputSection>(this, &Sec, Name); return InX::ARMAttributes; } return &InputSection::Discarded; + } case SHT_RELA: case SHT_REL: { // Find the relocation target section and associate this @@ -443,13 +516,12 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { size_t NumRelocations; if (Sec.sh_type == SHT_RELA) { - ArrayRef<Elf_Rela> Rels = - check(this->getObj().relas(&Sec), toString(this)); + ArrayRef<Elf_Rela> Rels = CHECK(this->getObj().relas(&Sec), this); Target->FirstRelocation = Rels.begin(); NumRelocations = Rels.size(); Target->AreRelocsRela = true; } else { - ArrayRef<Elf_Rel> Rels = check(this->getObj().rels(&Sec), toString(this)); + ArrayRef<Elf_Rel> Rels = CHECK(this->getObj().rels(&Sec), this); Target->FirstRelocation = Rels.begin(); NumRelocations = Rels.size(); Target->AreRelocsRela = false; @@ -497,18 +569,6 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { return &InputSection::Discarded; } - if (Config->Strip != StripPolicy::None && Name.startswith(".debug")) - return &InputSection::Discarded; - - // If -gdb-index is given, LLD creates .gdb_index section, and that - // section serves the same purpose as .debug_gnu_pub{names,types} sections. - // If that's the case, we want to eliminate .debug_gnu_pub{names,types} - // because they are redundant and can waste large amount of disk space - // (for example, they are about 400 MiB in total for a clang debug build.) - if (Config->GdbIndex && - (Name == ".debug_gnu_pubnames" || Name == ".debug_gnu_pubtypes")) - return &InputSection::Discarded; - // The linkonce feature is a sort of proto-comdat. Some glibc i386 object // files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce // sections. Drop those sections to avoid duplicate symbol errors. @@ -529,46 +589,24 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { } template <class ELFT> -StringRef elf::ObjectFile<ELFT>::getSectionName(const Elf_Shdr &Sec) { - return check(this->getObj().getSectionName(&Sec, SectionStringTable), - toString(this)); -} - -template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() { - SymbolBodies.reserve(this->Symbols.size()); - for (const Elf_Sym &Sym : this->Symbols) - SymbolBodies.push_back(createSymbolBody(&Sym)); +StringRef ObjFile<ELFT>::getSectionName(const Elf_Shdr &Sec) { + return CHECK(this->getObj().getSectionName(&Sec, SectionStringTable), this); } -template <class ELFT> -InputSectionBase *elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const { - uint32_t Index = this->getSectionIndex(Sym); - if (Index >= this->Sections.size()) - fatal(toString(this) + ": invalid section index: " + Twine(Index)); - InputSectionBase *S = this->Sections[Index]; - - // We found that GNU assembler 2.17.50 [FreeBSD] 2007-07-03 could - // generate broken objects. STT_SECTION/STT_NOTYPE symbols can be - // associated with SHT_REL[A]/SHT_SYMTAB/SHT_STRTAB sections. - // In this case it is fine for section to be null here as we do not - // allocate sections of these types. - if (!S) { - if (Index == 0 || Sym.getType() == STT_SECTION || - Sym.getType() == STT_NOTYPE) - return nullptr; - fatal(toString(this) + ": invalid section index: " + Twine(Index)); - } - - if (S == &InputSection::Discarded) - return S; - return S->Repl; +template <class ELFT> void ObjFile<ELFT>::initializeSymbols() { + this->Symbols.reserve(this->ELFSyms.size()); + for (const Elf_Sym &Sym : this->ELFSyms) + this->Symbols.push_back(createSymbol(&Sym)); } -template <class ELFT> -SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) { +template <class ELFT> Symbol *ObjFile<ELFT>::createSymbol(const Elf_Sym *Sym) { int Binding = Sym->getBinding(); - InputSectionBase *Sec = getSection(*Sym); + uint32_t SecIdx = this->getSectionIndex(*Sym); + if (SecIdx >= this->Sections.size()) + fatal(toString(this) + ": invalid section index: " + Twine(SecIdx)); + + InputSectionBase *Sec = this->Sections[SecIdx]; uint8_t StOther = Sym->st_other; uint8_t Type = Sym->getType(); uint64_t Value = Sym->st_value; @@ -576,34 +614,29 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) { if (Binding == STB_LOCAL) { if (Sym->getType() == STT_FILE) - SourceFile = check(Sym->getName(this->StringTable), toString(this)); + SourceFile = CHECK(Sym->getName(this->StringTable), this); if (this->StringTable.size() <= Sym->st_name) fatal(toString(this) + ": invalid symbol name offset"); StringRefZ Name = this->StringTable.data() + Sym->st_name; if (Sym->st_shndx == SHN_UNDEF) - return make<Undefined>(Name, /*IsLocal=*/true, StOther, Type, this); + return make<Undefined>(this, Name, Binding, StOther, Type); - return make<DefinedRegular>(Name, /*IsLocal=*/true, StOther, Type, Value, - Size, Sec, this); + return make<Defined>(this, Name, Binding, StOther, Type, Value, Size, Sec); } - StringRef Name = check(Sym->getName(this->StringTable), toString(this)); + StringRef Name = CHECK(Sym->getName(this->StringTable), this); switch (Sym->st_shndx) { case SHN_UNDEF: - return elf::Symtab<ELFT>::X - ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type, - /*CanOmitFromDynSym=*/false, this) - ->body(); + return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type, + /*CanOmitFromDynSym=*/false, this); case SHN_COMMON: if (Value == 0 || Value >= UINT32_MAX) fatal(toString(this) + ": common symbol '" + Name + "' has invalid alignment: " + Twine(Value)); - return elf::Symtab<ELFT>::X - ->addCommon(Name, Size, Value, Binding, StOther, Type, this) - ->body(); + return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, this); } switch (Binding) { @@ -613,13 +646,10 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) { case STB_WEAK: case STB_GNU_UNIQUE: if (Sec == &InputSection::Discarded) - return elf::Symtab<ELFT>::X - ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type, - /*CanOmitFromDynSym=*/false, this) - ->body(); - return elf::Symtab<ELFT>::X - ->addRegular(Name, StOther, Type, Value, Size, Binding, Sec, this) - ->body(); + return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type, + /*CanOmitFromDynSym=*/false, this); + return Symtab->addRegular<ELFT>(Name, StOther, Type, Value, Size, Binding, + Sec, this); } } @@ -630,14 +660,14 @@ ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File) template <class ELFT> void ArchiveFile::parse() { Symbols.reserve(File->getNumberOfSymbols()); for (const Archive::Symbol &Sym : File->symbols()) - Symbols.push_back(Symtab<ELFT>::X->addLazyArchive(this, Sym)); + Symbols.push_back(Symtab->addLazyArchive<ELFT>(Sym.getName(), this, Sym)); } // Returns a buffer pointing to a member file containing a given symbol. std::pair<MemoryBufferRef, uint64_t> ArchiveFile::getMember(const Archive::Symbol *Sym) { Archive::Child C = - check(Sym->getMember(), toString(this) + + CHECK(Sym->getMember(), toString(this) + ": could not get the member for symbol " + Sym->getName()); @@ -645,14 +675,13 @@ ArchiveFile::getMember(const Archive::Symbol *Sym) { return {MemoryBufferRef(), 0}; MemoryBufferRef Ret = - check(C.getMemoryBufferRef(), + CHECK(C.getMemoryBufferRef(), toString(this) + ": could not get the buffer for the member defining symbol " + Sym->getName()); if (C.getParent()->isThin() && Tar) - Tar->append(relativeToRoot(check(C.getFullName(), toString(this))), - Ret.getBuffer()); + Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), Ret.getBuffer()); if (C.getParent()->isThin()) return {Ret, 0}; return {Ret, C.getChildOffset()}; @@ -661,22 +690,14 @@ ArchiveFile::getMember(const Archive::Symbol *Sym) { template <class ELFT> SharedFile<ELFT>::SharedFile(MemoryBufferRef M, StringRef DefaultSoName) : ELFFileBase<ELFT>(Base::SharedKind, M), SoName(DefaultSoName), - AsNeeded(Config->AsNeeded) {} - -template <class ELFT> -const typename ELFT::Shdr * -SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const { - return check( - this->getObj().getSection(&Sym, this->Symbols, this->SymtabSHNDX), - toString(this)); -} + IsNeeded(!Config->AsNeeded) {} // Partially parse the shared object file so that we can call // getSoName on this object. template <class ELFT> void SharedFile<ELFT>::parseSoName() { const Elf_Shdr *DynamicSec = nullptr; const ELFFile<ELFT> Obj = this->getObj(); - ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this)); + ArrayRef<Elf_Shdr> Sections = CHECK(Obj.sections(), this); // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d. for (const Elf_Shdr &Sec : Sections) { @@ -690,8 +711,7 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() { DynamicSec = &Sec; break; case SHT_SYMTAB_SHNDX: - this->SymtabSHNDX = - check(Obj.getSHNDXTable(Sec, Sections), toString(this)); + this->SymtabSHNDX = CHECK(Obj.getSHNDXTable(Sec, Sections), this); break; case SHT_GNU_versym: this->VersymSec = &Sec; @@ -702,15 +722,14 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() { } } - if (this->VersymSec && this->Symbols.empty()) + if (this->VersymSec && this->ELFSyms.empty()) error("SHT_GNU_versym should be associated with symbol table"); // Search for a DT_SONAME tag to initialize this->SoName. if (!DynamicSec) return; ArrayRef<Elf_Dyn> Arr = - check(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec), - toString(this)); + CHECK(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec), this); for (const Elf_Dyn &Dyn : Arr) { if (Dyn.d_tag == DT_SONAME) { uint64_t Val = Dyn.getVal(); @@ -767,11 +786,14 @@ SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) { template <class ELFT> void SharedFile<ELFT>::parseRest() { // Create mapping from version identifiers to Elf_Verdef entries. const Elf_Versym *Versym = nullptr; - std::vector<const Elf_Verdef *> Verdefs = parseVerdefs(Versym); + Verdefs = parseVerdefs(Versym); - Elf_Sym_Range Syms = this->getGlobalSymbols(); + ArrayRef<Elf_Shdr> Sections = CHECK(this->getObj().sections(), this); + + // Add symbols to the symbol table. + Elf_Sym_Range Syms = this->getGlobalELFSyms(); for (const Elf_Sym &Sym : Syms) { - unsigned VersymIndex = 0; + unsigned VersymIndex = VER_NDX_GLOBAL; if (Versym) { VersymIndex = Versym->vs_index; ++Versym; @@ -779,28 +801,54 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() { bool Hidden = VersymIndex & VERSYM_HIDDEN; VersymIndex = VersymIndex & ~VERSYM_HIDDEN; - StringRef Name = check(Sym.getName(this->StringTable), toString(this)); + StringRef Name = CHECK(Sym.getName(this->StringTable), this); if (Sym.isUndefined()) { Undefs.push_back(Name); continue; } - // Ignore local symbols. - if (Versym && VersymIndex == VER_NDX_LOCAL) + if (Sym.getBinding() == STB_LOCAL) { + warn("found local symbol '" + Name + + "' in global part of symbol table in file " + toString(this)); continue; + } + + const Elf_Verdef *Ver = nullptr; + if (VersymIndex != VER_NDX_GLOBAL) { + if (VersymIndex >= Verdefs.size() || VersymIndex == VER_NDX_LOCAL) { + error("corrupt input file: version definition index " + + Twine(VersymIndex) + " for symbol " + Name + + " is out of bounds\n>>> defined in " + toString(this)); + continue; + } + Ver = Verdefs[VersymIndex]; + } else { + VersymIndex = 0; + } - const Elf_Verdef *V = - VersymIndex == VER_NDX_GLOBAL ? nullptr : Verdefs[VersymIndex]; + // We do not usually care about alignments of data in shared object + // files because the loader takes care of it. However, if we promote a + // DSO symbol to point to .bss due to copy relocation, we need to keep + // the original alignment requirements. We infer it here. + uint64_t Alignment = 1; + if (Sym.st_value) + Alignment = 1ULL << countTrailingZeros((uint64_t)Sym.st_value); + if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size()) { + uint64_t SecAlign = Sections[Sym.st_shndx].sh_addralign; + Alignment = std::min(Alignment, SecAlign); + } + if (Alignment > UINT32_MAX) + error(toString(this) + ": alignment too large: " + Name); if (!Hidden) - elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V); + Symtab->addShared(Name, this, Sym, Alignment, VersymIndex); // Also add the symbol with the versioned name to handle undefined symbols // with explicit versions. - if (V) { - StringRef VerName = this->StringTable.data() + V->getAux()->vda_name; + if (Ver) { + StringRef VerName = this->StringTable.data() + Ver->getAux()->vda_name; Name = Saver.save(Name + "@" + VerName); - elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V); + Symtab->addShared(Name, this, Sym, Alignment, VersymIndex); } } } @@ -855,7 +903,7 @@ BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName, MemoryBufferRef MBRef(MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier() + utostr(OffsetInArchive))); - Obj = check(lto::InputFile::create(MBRef), toString(this)); + Obj = CHECK(lto::InputFile::create(MBRef), this); Triple T(Obj->getTargetTriple()); EKind = getBitcodeELFKind(T); @@ -887,22 +935,20 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats, int C = ObjSym.getComdatIndex(); if (C != -1 && !KeptComdats[C]) - return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding, - Visibility, Type, CanOmitFromDynSym, - F); + return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type, + CanOmitFromDynSym, F); if (ObjSym.isUndefined()) - return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding, - Visibility, Type, CanOmitFromDynSym, - F); + return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type, + CanOmitFromDynSym, F); if (ObjSym.isCommon()) - return Symtab<ELFT>::X->addCommon(NameRef, ObjSym.getCommonSize(), - ObjSym.getCommonAlignment(), Binding, - Visibility, STT_OBJECT, F); + return Symtab->addCommon(NameRef, ObjSym.getCommonSize(), + ObjSym.getCommonAlignment(), Binding, Visibility, + STT_OBJECT, F); - return Symtab<ELFT>::X->addBitcode(NameRef, Binding, Visibility, Type, - CanOmitFromDynSym, F); + return Symtab->addBitcode(NameRef, Binding, Visibility, Type, + CanOmitFromDynSym, F); } template <class ELFT> @@ -947,18 +993,15 @@ template <class ELFT> void BinaryFile::parse() { // characters in a filename are replaced with underscore. std::string S = "_binary_" + MB.getBufferIdentifier().str(); for (size_t I = 0; I < S.size(); ++I) - if (!isalnum(S[I])) + if (!isAlnum(S[I])) S[I] = '_'; - elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_start"), STV_DEFAULT, - STT_OBJECT, 0, 0, STB_GLOBAL, Section, - nullptr); - elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_end"), STV_DEFAULT, - STT_OBJECT, Data.size(), 0, STB_GLOBAL, - Section, nullptr); - elf::Symtab<ELFT>::X->addRegular(Saver.save(S + "_size"), STV_DEFAULT, - STT_OBJECT, Data.size(), 0, STB_GLOBAL, - nullptr, nullptr); + Symtab->addRegular<ELFT>(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, + 0, 0, STB_GLOBAL, Section, nullptr); + Symtab->addRegular<ELFT>(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT, + Data.size(), 0, STB_GLOBAL, Section, nullptr); + Symtab->addRegular<ELFT>(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT, + Data.size(), 0, STB_GLOBAL, nullptr, nullptr); } static bool isBitcode(MemoryBufferRef MB) { @@ -973,13 +1016,13 @@ InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, switch (getELFKind(MB)) { case ELF32LEKind: - return make<ObjectFile<ELF32LE>>(MB, ArchiveName); + return make<ObjFile<ELF32LE>>(MB, ArchiveName); case ELF32BEKind: - return make<ObjectFile<ELF32BE>>(MB, ArchiveName); + return make<ObjFile<ELF32BE>>(MB, ArchiveName); case ELF64LEKind: - return make<ObjectFile<ELF64LE>>(MB, ArchiveName); + return make<ObjFile<ELF64LE>>(MB, ArchiveName); case ELF64BEKind: - return make<ObjectFile<ELF64BE>>(MB, ArchiveName); + return make<ObjFile<ELF64BE>>(MB, ArchiveName); default: llvm_unreachable("getELFKind"); } @@ -1000,53 +1043,53 @@ InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) { } } -MemoryBufferRef LazyObjectFile::getBuffer() { +MemoryBufferRef LazyObjFile::getBuffer() { if (Seen) return MemoryBufferRef(); Seen = true; return MB; } -InputFile *LazyObjectFile::fetch() { +InputFile *LazyObjFile::fetch() { MemoryBufferRef MBRef = getBuffer(); if (MBRef.getBuffer().empty()) return nullptr; return createObjectFile(MBRef, ArchiveName, OffsetInArchive); } -template <class ELFT> void LazyObjectFile::parse() { - for (StringRef Sym : getSymbols()) - Symtab<ELFT>::X->addLazyObject(Sym, *this); +template <class ELFT> void LazyObjFile::parse() { + for (StringRef Sym : getSymbolNames()) + Symtab->addLazyObject<ELFT>(Sym, *this); } -template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() { +template <class ELFT> std::vector<StringRef> LazyObjFile::getElfSymbols() { typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::SymRange Elf_Sym_Range; - const ELFFile<ELFT> Obj(this->MB.getBuffer()); - ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this)); + ELFFile<ELFT> Obj = check(ELFFile<ELFT>::create(this->MB.getBuffer())); + ArrayRef<Elf_Shdr> Sections = CHECK(Obj.sections(), this); for (const Elf_Shdr &Sec : Sections) { if (Sec.sh_type != SHT_SYMTAB) continue; - Elf_Sym_Range Syms = check(Obj.symbols(&Sec), toString(this)); + Elf_Sym_Range Syms = CHECK(Obj.symbols(&Sec), this); uint32_t FirstNonLocal = Sec.sh_info; StringRef StringTable = - check(Obj.getStringTableForSymtab(Sec, Sections), toString(this)); + CHECK(Obj.getStringTableForSymtab(Sec, Sections), this); std::vector<StringRef> V; for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal)) if (Sym.st_shndx != SHN_UNDEF) - V.push_back(check(Sym.getName(StringTable), toString(this))); + V.push_back(CHECK(Sym.getName(StringTable), this)); return V; } return {}; } -std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() { +std::vector<StringRef> LazyObjFile::getBitcodeSymbols() { std::unique_ptr<lto::InputFile> Obj = - check(lto::InputFile::create(this->MB), toString(this)); + CHECK(lto::InputFile::create(this->MB), this); std::vector<StringRef> V; for (const lto::InputFile::Symbol &Sym : Obj->symbols()) if (!Sym.isUndefined()) @@ -1055,7 +1098,7 @@ std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() { } // Returns a vector of globally-visible defined symbol names. -std::vector<StringRef> LazyObjectFile::getSymbols() { +std::vector<StringRef> LazyObjFile::getSymbolNames() { if (isBitcode(this->MB)) return getBitcodeSymbols(); @@ -1083,20 +1126,20 @@ template void BitcodeFile::parse<ELF32BE>(DenseSet<CachedHashStringRef> &); template void BitcodeFile::parse<ELF64LE>(DenseSet<CachedHashStringRef> &); template void BitcodeFile::parse<ELF64BE>(DenseSet<CachedHashStringRef> &); -template void LazyObjectFile::parse<ELF32LE>(); -template void LazyObjectFile::parse<ELF32BE>(); -template void LazyObjectFile::parse<ELF64LE>(); -template void LazyObjectFile::parse<ELF64BE>(); +template void LazyObjFile::parse<ELF32LE>(); +template void LazyObjFile::parse<ELF32BE>(); +template void LazyObjFile::parse<ELF64LE>(); +template void LazyObjFile::parse<ELF64BE>(); template class elf::ELFFileBase<ELF32LE>; template class elf::ELFFileBase<ELF32BE>; template class elf::ELFFileBase<ELF64LE>; template class elf::ELFFileBase<ELF64BE>; -template class elf::ObjectFile<ELF32LE>; -template class elf::ObjectFile<ELF32BE>; -template class elf::ObjectFile<ELF64LE>; -template class elf::ObjectFile<ELF64BE>; +template class elf::ObjFile<ELF32LE>; +template class elf::ObjFile<ELF32BE>; +template class elf::ObjFile<ELF64LE>; +template class elf::ObjFile<ELF64BE>; template class elf::SharedFile<ELF32LE>; template class elf::SharedFile<ELF32BE>; diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h index 006218b45d9e..427f2fdea53e 100644 --- a/ELF/InputFiles.h +++ b/ELF/InputFiles.h @@ -11,12 +11,10 @@ #define LLD_ELF_INPUT_FILES_H #include "Config.h" -#include "Error.h" -#include "InputSection.h" -#include "Symbols.h" +#include "lld/Common/ErrorHandler.h" -#include "lld/Core/LLVM.h" -#include "lld/Core/Reproduce.h" +#include "lld/Common/LLVM.h" +#include "lld/Common/Reproduce.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" @@ -40,9 +38,10 @@ class InputFile; namespace lld { namespace elf { class InputFile; +class InputSectionBase; } -// Returns "(internal)", "foo.a(bar.o)" or "baz.o". +// Returns "<internal>", "foo.a(bar.o)" or "baz.o". std::string toString(const elf::InputFile *F); namespace elf { @@ -50,7 +49,7 @@ namespace elf { using llvm::object::Archive; class Lazy; -class SymbolBody; +class Symbol; // If -reproduce option is given, all input files are written // to this tar archive. @@ -63,9 +62,9 @@ llvm::Optional<MemoryBufferRef> readFile(StringRef Path); class InputFile { public: enum Kind { - ObjectKind, + ObjKind, SharedKind, - LazyObjectKind, + LazyObjKind, ArchiveKind, BitcodeKind, BinaryKind, @@ -79,10 +78,18 @@ public: // Returns sections. It is a runtime error to call this function // on files that don't have the notion of sections. ArrayRef<InputSectionBase *> getSections() const { - assert(FileKind == ObjectKind || FileKind == BinaryKind); + assert(FileKind == ObjKind || FileKind == BinaryKind); return Sections; } + // Returns object file symbols. It is a runtime error to call this + // function on files of other types. + ArrayRef<Symbol *> getSymbols() { + assert(FileKind == ObjKind || FileKind == BitcodeKind || + FileKind == ArchiveKind); + return Symbols; + } + // Filename of .a which contained this file. If this file was // not in an archive file, it is the empty string. We use this // string for creating error messages. @@ -100,6 +107,7 @@ public: protected: InputFile(Kind K, MemoryBufferRef M); std::vector<InputSectionBase *> Sections; + std::vector<Symbol *> Symbols; private: const Kind FileKind; @@ -115,21 +123,22 @@ public: ELFFileBase(Kind K, MemoryBufferRef M); static bool classof(const InputFile *F) { Kind K = F->kind(); - return K == ObjectKind || K == SharedKind; + return K == ObjKind || K == SharedKind; } llvm::object::ELFFile<ELFT> getObj() const { - return llvm::object::ELFFile<ELFT>(MB.getBuffer()); + return check(llvm::object::ELFFile<ELFT>::create(MB.getBuffer())); } StringRef getStringTable() const { return StringTable; } uint32_t getSectionIndex(const Elf_Sym &Sym) const; - Elf_Sym_Range getGlobalSymbols(); + Elf_Sym_Range getGlobalELFSyms(); + Elf_Sym_Range getELFSyms() const { return ELFSyms; } protected: - ArrayRef<Elf_Sym> Symbols; + ArrayRef<Elf_Sym> ELFSyms; uint32_t FirstNonLocal = 0; ArrayRef<Elf_Word> SymtabSHNDX; StringRef StringTable; @@ -137,7 +146,7 @@ protected: }; // .o file. -template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> { +template <class ELFT> class ObjFile : public ELFFileBase<ELFT> { typedef ELFFileBase<ELFT> Base; typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; @@ -150,34 +159,29 @@ template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> { ArrayRef<Elf_Word> getShtGroupEntries(const Elf_Shdr &Sec); public: - static bool classof(const InputFile *F) { - return F->kind() == Base::ObjectKind; - } + static bool classof(const InputFile *F) { return F->kind() == Base::ObjKind; } - ArrayRef<SymbolBody *> getSymbols(); - ArrayRef<SymbolBody *> getLocalSymbols(); + ArrayRef<Symbol *> getLocalSymbols(); - ObjectFile(MemoryBufferRef M, StringRef ArchiveName); + ObjFile(MemoryBufferRef M, StringRef ArchiveName); void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups); - InputSectionBase *getSection(const Elf_Sym &Sym) const; - - SymbolBody &getSymbolBody(uint32_t SymbolIndex) const { - if (SymbolIndex >= SymbolBodies.size()) + Symbol &getSymbol(uint32_t SymbolIndex) const { + if (SymbolIndex >= this->Symbols.size()) fatal(toString(this) + ": invalid symbol index"); - return *SymbolBodies[SymbolIndex]; + return *this->Symbols[SymbolIndex]; } - template <typename RelT> - SymbolBody &getRelocTargetSym(const RelT &Rel) const { + template <typename RelT> Symbol &getRelocTargetSym(const RelT &Rel) const { uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); - return getSymbolBody(SymIndex); + return getSymbol(SymIndex); } // Returns source line information for a given offset. // If no information is available, returns "". std::string getLineInfo(InputSectionBase *S, uint64_t Offset); llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t); + llvm::Optional<std::pair<std::string, unsigned>> getVariableLoc(StringRef Name); // MIPS GP0 value defined by this file. This value represents the gp value // used to create the relocatable object and required to support @@ -193,16 +197,13 @@ private: void initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups); void initializeSymbols(); - void initializeDwarfLine(); + void initializeDwarf(); InputSectionBase *getRelocTarget(const Elf_Shdr &Sec); InputSectionBase *createInputSection(const Elf_Shdr &Sec); StringRef getSectionName(const Elf_Shdr &Sec); bool shouldMerge(const Elf_Shdr &Sec); - SymbolBody *createSymbolBody(const Elf_Sym *Sym); - - // List of all symbols referenced or defined by this file. - std::vector<SymbolBody *> SymbolBodies; + Symbol *createSymbol(const Elf_Sym *Sym); // .shstrtab contents. StringRef SectionStringTable; @@ -212,34 +213,33 @@ private: // single object file, so we cache debugging information in order to // parse it only once for each object file we link. std::unique_ptr<llvm::DWARFDebugLine> DwarfLine; + llvm::DenseMap<StringRef, std::pair<unsigned, unsigned>> VariableLoc; llvm::once_flag InitDwarfLine; }; -// LazyObjectFile is analogous to ArchiveFile in the sense that +// LazyObjFile is analogous to ArchiveFile in the sense that // the file contains lazy symbols. The difference is that -// LazyObjectFile wraps a single file instead of multiple files. +// LazyObjFile wraps a single file instead of multiple files. // // This class is used for --start-lib and --end-lib options which // instruct the linker to link object files between them with the // archive file semantics. -class LazyObjectFile : public InputFile { +class LazyObjFile : public InputFile { public: - LazyObjectFile(MemoryBufferRef M, StringRef ArchiveName, - uint64_t OffsetInArchive) - : InputFile(LazyObjectKind, M), OffsetInArchive(OffsetInArchive) { + LazyObjFile(MemoryBufferRef M, StringRef ArchiveName, + uint64_t OffsetInArchive) + : InputFile(LazyObjKind, M), OffsetInArchive(OffsetInArchive) { this->ArchiveName = ArchiveName; } - static bool classof(const InputFile *F) { - return F->kind() == LazyObjectKind; - } + static bool classof(const InputFile *F) { return F->kind() == LazyObjKind; } template <class ELFT> void parse(); MemoryBufferRef getBuffer(); InputFile *fetch(); private: - std::vector<StringRef> getSymbols(); + std::vector<StringRef> getSymbolNames(); template <class ELFT> std::vector<StringRef> getElfSymbols(); std::vector<StringRef> getBitcodeSymbols(); @@ -253,7 +253,6 @@ public: explicit ArchiveFile(std::unique_ptr<Archive> &&File); static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } template <class ELFT> void parse(); - ArrayRef<Symbol *> getSymbols() { return Symbols; } // Returns a memory buffer for a given symbol and the offset in the archive // for the member. An empty memory buffer and an offset of zero @@ -264,7 +263,6 @@ public: private: std::unique_ptr<Archive> File; llvm::DenseSet<uint64_t> Seen; - std::vector<Symbol *> Symbols; }; class BitcodeFile : public InputFile { @@ -274,11 +272,7 @@ public: static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } template <class ELFT> void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups); - ArrayRef<Symbol *> getSymbols() { return Symbols; } std::unique_ptr<llvm::lto::InputFile> Obj; - -private: - std::vector<Symbol *> Symbols; }; // .so file. @@ -296,9 +290,9 @@ template <class ELFT> class SharedFile : public ELFFileBase<ELFT> { const Elf_Shdr *VerdefSec = nullptr; public: + std::vector<const Elf_Verdef *> Verdefs; std::string SoName; - const Elf_Shdr *getSection(const Elf_Sym &Sym) const; llvm::ArrayRef<StringRef> getUndefinedSymbols() { return Undefs; } static bool classof(const InputFile *F) { @@ -324,9 +318,7 @@ public: std::map<const Elf_Verdef *, NeededVer> VerdefMap; // Used for --as-needed - bool AsNeeded = false; - bool IsUsed = false; - bool isNeeded() const { return !AsNeeded || IsUsed; } + bool IsNeeded; }; class BinaryFile : public InputFile { @@ -340,6 +332,11 @@ InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "", uint64_t OffsetInArchive = 0); InputFile *createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName); +extern std::vector<BinaryFile *> BinaryFiles; +extern std::vector<BitcodeFile *> BitcodeFiles; +extern std::vector<InputFile *> ObjectFiles; +extern std::vector<InputFile *> SharedFiles; + } // namespace elf } // namespace lld diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index c6a539b8dfa5..02cad56ca508 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -10,21 +10,23 @@ #include "InputSection.h" #include "Config.h" #include "EhFrame.h" -#include "Error.h" #include "InputFiles.h" #include "LinkerScript.h" -#include "Memory.h" #include "OutputSections.h" #include "Relocations.h" +#include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm/Object/Decompressor.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Path.h" #include "llvm/Support/Threading.h" +#include "llvm/Support/xxhash.h" #include <mutex> using namespace llvm; @@ -44,8 +46,34 @@ std::string lld::toString(const InputSectionBase *Sec) { return (toString(Sec->File) + ":(" + Sec->Name + ")").str(); } +DenseMap<SectionBase *, int> elf::buildSectionOrder() { + DenseMap<SectionBase *, int> SectionOrder; + if (Config->SymbolOrderingFile.empty()) + return SectionOrder; + + // Build a map from symbols to their priorities. Symbols that didn't + // appear in the symbol ordering file have the lowest priority 0. + // All explicitly mentioned symbols have negative (higher) priorities. + DenseMap<StringRef, int> SymbolOrder; + int Priority = -Config->SymbolOrderingFile.size(); + for (StringRef S : Config->SymbolOrderingFile) + SymbolOrder.insert({S, Priority++}); + + // Build a map from sections to their priorities. + for (InputFile *File : ObjectFiles) { + for (Symbol *Sym : File->getSymbols()) { + auto *D = dyn_cast<Defined>(Sym); + if (!D || !D->Section) + continue; + int &Priority = SectionOrder[D->Section]; + Priority = std::min(Priority, SymbolOrder.lookup(D->getName())); + } + } + return SectionOrder; +} + template <class ELFT> -static ArrayRef<uint8_t> getSectionContents(elf::ObjectFile<ELFT> *File, +static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> *File, const typename ELFT::Shdr *Hdr) { if (!File || Hdr->sh_type == SHT_NOBITS) return makeArrayRef<uint8_t>(nullptr, Hdr->sh_size); @@ -59,9 +87,7 @@ InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags, StringRef Name, Kind SectionKind) : SectionBase(SectionKind, Name, Flags, Entsize, Alignment, Type, Info, Link), - File(File), Data(Data), Repl(this) { - Live = !Config->GcSections || !(Flags & SHF_ALLOC); - Assigned = false; + File(File), Data(Data) { NumRelocations = 0; AreRelocsRela = false; @@ -102,7 +128,7 @@ static uint64_t getType(uint64_t Type, StringRef Name) { } template <class ELFT> -InputSectionBase::InputSectionBase(elf::ObjectFile<ELFT> *File, +InputSectionBase::InputSectionBase(ObjFile<ELFT> *File, const typename ELFT::Shdr *Hdr, StringRef Name, Kind SectionKind) : InputSectionBase(File, getFlags(Hdr->sh_flags), @@ -160,7 +186,7 @@ uint64_t SectionBase::getOffset(uint64_t Offset) const { OutputSection *SectionBase::getOutputSection() { InputSection *Sec; if (auto *IS = dyn_cast<InputSection>(this)) - Sec = IS; + return IS->getParent(); else if (auto *MS = dyn_cast<MergeInputSection>(this)) Sec = MS->getParent(); else if (auto *EH = dyn_cast<EhInputSection>(this)) @@ -170,29 +196,23 @@ OutputSection *SectionBase::getOutputSection() { return Sec ? Sec->getParent() : nullptr; } -// Uncompress section contents. Note that this function is called -// from parallel_for_each, so it must be thread-safe. -void InputSectionBase::uncompress() { +// Uncompress section contents if required. Note that this function +// is called from parallelForEach, so it must be thread-safe. +void InputSectionBase::maybeUncompress() { + if (UncompressBuf || !Decompressor::isCompressedELFSection(Flags, Name)) + return; + Decompressor Dec = check(Decompressor::create(Name, toStringRef(Data), Config->IsLE, Config->Is64)); size_t Size = Dec.getDecompressedSize(); - char *OutputBuf; - { - static std::mutex Mu; - std::lock_guard<std::mutex> Lock(Mu); - OutputBuf = BAlloc.Allocate<char>(Size); - } - - if (Error E = Dec.decompress({OutputBuf, Size})) + UncompressBuf.reset(new char[Size]()); + if (Error E = Dec.decompress({UncompressBuf.get(), Size})) fatal(toString(this) + ": decompress failed: " + llvm::toString(std::move(E))); - this->Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size); - this->Flags &= ~(uint64_t)SHF_COMPRESSED; -} -uint64_t SectionBase::getOffset(const DefinedRegular &Sym) const { - return getOffset(Sym.Value); + this->Data = makeArrayRef((uint8_t *)UncompressBuf.get(), Size); + this->Flags &= ~(uint64_t)SHF_COMPRESSED; } InputSection *InputSectionBase::getLinkOrderDep() const { @@ -200,9 +220,9 @@ InputSection *InputSectionBase::getLinkOrderDep() const { InputSectionBase *L = File->getSections()[Link]; if (auto *IS = dyn_cast<InputSection>(L)) return IS; - error( - "Merge and .eh_frame sections are not supported with SHF_LINK_ORDER " + - toString(L)); + error("a section with SHF_LINK_ORDER should not refer a non-regular " + "section: " + + toString(L)); } return nullptr; } @@ -227,8 +247,8 @@ std::string InputSectionBase::getLocation(uint64_t Offset) { SrcFile = toString(File); // Find a function symbol that encloses a given location. - for (SymbolBody *B : getFile<ELFT>()->getSymbols()) - if (auto *D = dyn_cast<DefinedRegular>(B)) + for (Symbol *B : File->getSymbols()) + if (auto *D = dyn_cast<Defined>(B)) if (D->Section == this && D->Type == STT_FUNC) if (D->Value <= Offset && Offset < D->Value + D->Size) return SrcFile + ":(function " + toString(*D) + ")"; @@ -237,31 +257,40 @@ std::string InputSectionBase::getLocation(uint64_t Offset) { return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str(); } -// Returns a source location string. This function is intended to be -// used for constructing an error message. The returned message looks -// like this: +// Concatenates arguments to construct a string representing an error location. +static std::string createFileLineMsg(StringRef Path, unsigned Line) { + std::string Filename = path::filename(Path); + std::string Lineno = ":" + std::to_string(Line); + if (Filename == Path) + return Filename + Lineno; + return Filename + Lineno + " (" + Path.str() + Lineno + ")"; +} + +// This function is intended to be used for constructing an error message. +// The returned message looks like this: // // foo.c:42 (/home/alice/possibly/very/long/path/foo.c:42) // -// Returns an empty string if there's no way to get line info. -template <class ELFT> std::string InputSectionBase::getSrcMsg(uint64_t Offset) { +// Returns an empty string if there's no way to get line info. +template <class ELFT> +std::string InputSectionBase::getSrcMsg(const Symbol &Sym, uint64_t Offset) { // Synthetic sections don't have input files. - elf::ObjectFile<ELFT> *File = getFile<ELFT>(); + ObjFile<ELFT> *File = getFile<ELFT>(); if (!File) return ""; - Optional<DILineInfo> Info = File->getDILineInfo(this, Offset); + // In DWARF, functions and variables are stored to different places. + // First, lookup a function for a given offset. + if (Optional<DILineInfo> Info = File->getDILineInfo(this, Offset)) + return createFileLineMsg(Info->FileName, Info->Line); - // File->SourceFile contains STT_FILE symbol, and that is a last resort. - if (!Info) - return File->SourceFile; + // If it failed, lookup again as a variable. + if (Optional<std::pair<std::string, unsigned>> FileLine = + File->getVariableLoc(Sym.getName())) + return createFileLineMsg(FileLine->first, FileLine->second); - std::string Path = Info->FileName; - std::string Filename = path::filename(Path); - std::string Lineno = ":" + std::to_string(Info->Line); - if (Filename == Path) - return Filename + Lineno; - return Filename + Lineno + " (" + Path + Lineno + ")"; + // File->SourceFile contains STT_FILE symbol, and that is a last resort. + return File->SourceFile; } // Returns a filename string along with an optional section name. This @@ -273,11 +302,10 @@ template <class ELFT> std::string InputSectionBase::getSrcMsg(uint64_t Offset) { // or // // path/to/foo.o:(function bar) in archive path/to/bar.a -template <class ELFT> std::string InputSectionBase::getObjMsg(uint64_t Off) { +std::string InputSectionBase::getObjMsg(uint64_t Off) { // Synthetic sections don't have input files. - elf::ObjectFile<ELFT> *File = getFile<ELFT>(); if (!File) - return ("(internal):(" + Name + "+0x" + utohexstr(Off) + ")").str(); + return ("<internal>:(" + Name + "+0x" + utohexstr(Off) + ")").str(); std::string Filename = File->getName(); std::string Archive; @@ -285,8 +313,8 @@ template <class ELFT> std::string InputSectionBase::getObjMsg(uint64_t Off) { Archive = (" in archive " + File->ArchiveName).str(); // Find a symbol that encloses a given location. - for (SymbolBody *B : getFile<ELFT>()->getSymbols()) - if (auto *D = dyn_cast<DefinedRegular>(B)) + for (Symbol *B : File->getSymbols()) + if (auto *D = dyn_cast<Defined>(B)) if (D->Section == this && D->Value <= Off && Off < D->Value + D->Size) return Filename + ":(" + toString(*D) + ")" + Archive; @@ -295,7 +323,7 @@ template <class ELFT> std::string InputSectionBase::getObjMsg(uint64_t Off) { .str(); } -InputSectionBase InputSectionBase::Discarded; +InputSection InputSection::Discarded(0, 0, 0, ArrayRef<uint8_t>(), ""); InputSection::InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, ArrayRef<uint8_t> Data, StringRef Name, Kind K) @@ -304,8 +332,8 @@ InputSection::InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, Name, K) {} template <class ELFT> -InputSection::InputSection(elf::ObjectFile<ELFT> *F, - const typename ELFT::Shdr *Header, StringRef Name) +InputSection::InputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, + StringRef Name) : InputSectionBase(F, Header, Name, InputSectionBase::Regular) {} bool InputSection::classof(const SectionBase *S) { @@ -313,10 +341,6 @@ bool InputSection::classof(const SectionBase *S) { S->kind() == SectionBase::Synthetic; } -bool InputSectionBase::classof(const SectionBase *S) { - return S->kind() != Output; -} - OutputSection *InputSection::getParent() const { return cast_or_null<OutputSection>(Parent); } @@ -349,15 +373,11 @@ InputSectionBase *InputSection::getRelocatedSection() { // for each relocation. So we copy relocations one by one. template <class ELFT, class RelTy> void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { - InputSectionBase *RelocatedSection = getRelocatedSection(); + InputSectionBase *Sec = getRelocatedSection(); - // Loop is slow and have complexity O(N*M), where N - amount of - // relocations and M - amount of symbols in symbol table. - // That happens because getSymbolIndex(...) call below performs - // simple linear search. for (const RelTy &Rel : Rels) { - uint32_t Type = Rel.getType(Config->IsMips64EL); - SymbolBody &Body = this->getFile<ELFT>()->getRelocTargetSym(Rel); + RelType Type = Rel.getType(Config->IsMips64EL); + Symbol &Sym = this->getFile<ELFT>()->getRelocTargetSym(Rel); auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf); Buf += sizeof(RelTy); @@ -367,12 +387,11 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { // Output section VA is zero for -r, so r_offset is an offset within the // section, but for --emit-relocs it is an virtual address. - P->r_offset = RelocatedSection->getOutputSection()->Addr + - RelocatedSection->getOffset(Rel.r_offset); - P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Body), Type, + P->r_offset = Sec->getOutputSection()->Addr + Sec->getOffset(Rel.r_offset); + P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Sym), Type, Config->IsMips64EL); - if (Body.Type == STT_SECTION) { + if (Sym.Type == STT_SECTION) { // We combine multiple section symbols into only one per // section. This means we have to update the addend. That is // trivial for Elf_Rela, but for Elf_Rel we have to write to the @@ -382,19 +401,25 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { // avoid having to parse and recreate .eh_frame, we just replace any // relocation in it pointing to discarded sections with R_*_NONE, which // hopefully creates a frame that is ignored at runtime. - SectionBase *Section = cast<DefinedRegular>(Body).Section; + auto *D = dyn_cast<Defined>(&Sym); + if (!D) { + error("STT_SECTION symbol should be defined"); + continue; + } + SectionBase *Section = D->Section; if (Section == &InputSection::Discarded) { P->setSymbolAndType(0, 0, false); continue; } if (Config->IsRela) { - P->r_addend += Body.getVA() - Section->getOutputSection()->Addr; + P->r_addend = + Sym.getVA(getAddend<ELFT>(Rel)) - Section->getOutputSection()->Addr; } else if (Config->Relocatable) { - const uint8_t *BufLoc = RelocatedSection->Data.begin() + Rel.r_offset; - RelocatedSection->Relocations.push_back( - {R_ABS, Type, Rel.r_offset, Target->getImplicitAddend(BufLoc, Type), - &Body}); + const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset; + Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, + Target->getImplicitAddend(BufLoc, Type), + &Sym}); } } @@ -406,7 +431,7 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { // this context is the address of the place P. A further special case is that // branch relocations to an undefined weak reference resolve to the next // instruction. -static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A, +static uint32_t getARMUndefinedRelativeWeakVA(RelType Type, uint32_t A, uint32_t P) { switch (Type) { // Unresolved branch relocations to weak references resolve to next @@ -453,6 +478,7 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, case R_AARCH64_PREL32: case R_AARCH64_PREL64: case R_AARCH64_ADR_PREL_LO21: + case R_AARCH64_LD_PREL_LO19: return P + A; } llvm_unreachable("AArch64 pc-relative relocation expected\n"); @@ -461,53 +487,55 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, // ARM SBREL relocations are of the form S + A - B where B is the static base // The ARM ABI defines base to be "addressing origin of the output segment // defining the symbol S". We defined the "addressing origin"/static base to be -// the base of the PT_LOAD segment containing the Body. +// the base of the PT_LOAD segment containing the Sym. // The procedure call standard only defines a Read Write Position Independent // RWPI variant so in practice we should expect the static base to be the base // of the RW segment. -static uint64_t getARMStaticBase(const SymbolBody &Body) { - OutputSection *OS = Body.getOutputSection(); - if (!OS || !OS->FirstInPtLoad) - fatal("SBREL relocation to " + Body.getName() + " without static base"); - return OS->FirstInPtLoad->Addr; +static uint64_t getARMStaticBase(const Symbol &Sym) { + OutputSection *OS = Sym.getOutputSection(); + if (!OS || !OS->PtLoad || !OS->PtLoad->FirstSec) + fatal("SBREL relocation to " + Sym.getName() + " without static base"); + return OS->PtLoad->FirstSec->Addr; } -static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P, - const SymbolBody &Body, RelExpr Expr) { +static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P, + const Symbol &Sym, RelExpr Expr) { switch (Expr) { + case R_INVALID: + return 0; case R_ABS: case R_RELAX_GOT_PC_NOPIC: - return Body.getVA(A); + return Sym.getVA(A); case R_ARM_SBREL: - return Body.getVA(A) - getARMStaticBase(Body); + return Sym.getVA(A) - getARMStaticBase(Sym); case R_GOT: case R_RELAX_TLS_GD_TO_IE_ABS: - return Body.getGotVA() + A; + return Sym.getGotVA() + A; case R_GOTONLY_PC: return InX::Got->getVA() + A - P; case R_GOTONLY_PC_FROM_END: return InX::Got->getVA() + A - P + InX::Got->getSize(); case R_GOTREL: - return Body.getVA(A) - InX::Got->getVA(); + return Sym.getVA(A) - InX::Got->getVA(); case R_GOTREL_FROM_END: - return Body.getVA(A) - InX::Got->getVA() - InX::Got->getSize(); + return Sym.getVA(A) - InX::Got->getVA() - InX::Got->getSize(); case R_GOT_FROM_END: case R_RELAX_TLS_GD_TO_IE_END: - return Body.getGotOffset() + A - InX::Got->getSize(); + return Sym.getGotOffset() + A - InX::Got->getSize(); case R_GOT_OFF: - return Body.getGotOffset() + A; + return Sym.getGotOffset() + A; case R_GOT_PAGE_PC: case R_RELAX_TLS_GD_TO_IE_PAGE_PC: - return getAArch64Page(Body.getGotVA() + A) - getAArch64Page(P); + return getAArch64Page(Sym.getGotVA() + A) - getAArch64Page(P); case R_GOT_PC: case R_RELAX_TLS_GD_TO_IE: - return Body.getGotVA() + A - P; + return Sym.getGotVA() + A - P; case R_HINT: case R_NONE: case R_TLSDESC_CALL: llvm_unreachable("cannot relocate hint relocs"); case R_MIPS_GOTREL: - return Body.getVA(A) - InX::MipsGot->getGp(); + return Sym.getVA(A) - InX::MipsGot->getGp(); case R_MIPS_GOT_GP: return InX::MipsGot->getGp() + A; case R_MIPS_GOT_GP_PC: { @@ -515,42 +543,47 @@ static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P, // is _gp_disp symbol. In that case we should use the following // formula for calculation "AHL + GP - P + 4". For details see p. 4-19 at // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + // microMIPS variants of these relocations use slightly different + // expressions: AHL + GP - P + 3 for %lo() and AHL + GP - P - 1 for %hi() + // to correctly handle less-sugnificant bit of the microMIPS symbol. uint64_t V = InX::MipsGot->getGp() + A - P; - if (Type == R_MIPS_LO16) + if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16) V += 4; + if (Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_HI16) + V -= 1; return V; } case R_MIPS_GOT_LOCAL_PAGE: // If relocation against MIPS local symbol requires GOT entry, this entry // should be initialized by 'page address'. This address is high 16-bits // of sum the symbol's value and the addend. - return InX::MipsGot->getVA() + InX::MipsGot->getPageEntryOffset(Body, A) - + return InX::MipsGot->getVA() + InX::MipsGot->getPageEntryOffset(Sym, A) - InX::MipsGot->getGp(); case R_MIPS_GOT_OFF: case R_MIPS_GOT_OFF32: // In case of MIPS if a GOT relocation has non-zero addend this addend // should be applied to the GOT entry content not to the GOT entry offset. // That is why we use separate expression type. - return InX::MipsGot->getVA() + InX::MipsGot->getBodyEntryOffset(Body, A) - + return InX::MipsGot->getVA() + InX::MipsGot->getSymEntryOffset(Sym, A) - InX::MipsGot->getGp(); case R_MIPS_TLSGD: return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() + - InX::MipsGot->getGlobalDynOffset(Body) - InX::MipsGot->getGp(); + InX::MipsGot->getGlobalDynOffset(Sym) - InX::MipsGot->getGp(); case R_MIPS_TLSLD: return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() + InX::MipsGot->getTlsIndexOff() - InX::MipsGot->getGp(); case R_PAGE_PC: case R_PLT_PAGE_PC: { uint64_t Dest; - if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) + if (Sym.isUndefWeak()) Dest = getAArch64Page(A); else - Dest = getAArch64Page(Body.getVA(A)); + Dest = getAArch64Page(Sym.getVA(A)); return Dest - getAArch64Page(P); } case R_PC: { uint64_t Dest; - if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) { + if (Sym.isUndefWeak()) { // On ARM and AArch64 a branch to an undefined weak resolves to the // next instruction, otherwise the place. if (Config->EMachine == EM_ARM) @@ -558,19 +591,19 @@ static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P, else if (Config->EMachine == EM_AARCH64) Dest = getAArch64UndefinedRelativeWeakVA(Type, A, P); else - Dest = Body.getVA(A); + Dest = Sym.getVA(A); } else { - Dest = Body.getVA(A); + Dest = Sym.getVA(A); } return Dest - P; } case R_PLT: - return Body.getPltVA() + A; + return Sym.getPltVA() + A; case R_PLT_PC: case R_PPC_PLT_OPD: - return Body.getPltVA() + A - P; + return Sym.getPltVA() + A - P; case R_PPC_OPD: { - uint64_t SymVA = Body.getVA(A); + uint64_t SymVA = Sym.getVA(A); // If we have an undefined weak symbol, we might get here with a symbol // address of zero. That could overflow, but the code must be unreachable, // so don't bother doing anything at all. @@ -590,7 +623,7 @@ static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P, case R_PPC_TOC: return getPPC64TocBase() + A; case R_RELAX_GOT_PC: - return Body.getVA(A) - P; + return Sym.getVA(A) - P; case R_RELAX_TLS_GD_TO_LE: case R_RELAX_TLS_IE_TO_LE: case R_RELAX_TLS_LD_TO_LE: @@ -600,26 +633,25 @@ static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P, // lld and .tbss is not referenced, it gets reclaimed and we don't // create a TLS program header. Therefore, we resolve this // statically to zero. - if (Body.isTls() && (Body.isLazy() || Body.isUndefined()) && - Body.symbol()->isWeak()) + if (Sym.isTls() && Sym.isUndefWeak()) return 0; if (Target->TcbSize) - return Body.getVA(A) + alignTo(Target->TcbSize, Out::TlsPhdr->p_align); - return Body.getVA(A) - Out::TlsPhdr->p_memsz; + return Sym.getVA(A) + alignTo(Target->TcbSize, Out::TlsPhdr->p_align); + return Sym.getVA(A) - Out::TlsPhdr->p_memsz; case R_RELAX_TLS_GD_TO_LE_NEG: case R_NEG_TLS: - return Out::TlsPhdr->p_memsz - Body.getVA(A); + return Out::TlsPhdr->p_memsz - Sym.getVA(A); case R_SIZE: - return A; // Body.getSize was already folded into the addend. + return A; // Sym.getSize was already folded into the addend. case R_TLSDESC: - return InX::Got->getGlobalDynAddr(Body) + A; + return InX::Got->getGlobalDynAddr(Sym) + A; case R_TLSDESC_PAGE: - return getAArch64Page(InX::Got->getGlobalDynAddr(Body) + A) - + return getAArch64Page(InX::Got->getGlobalDynAddr(Sym) + A) - getAArch64Page(P); case R_TLSGD: - return InX::Got->getGlobalDynOffset(Body) + A - InX::Got->getSize(); + return InX::Got->getGlobalDynOffset(Sym) + A - InX::Got->getSize(); case R_TLSGD_PC: - return InX::Got->getGlobalDynAddr(Body) + A - P; + return InX::Got->getGlobalDynAddr(Sym) + A - P; case R_TLSLD: return InX::Got->getTlsIndexOff() + A - InX::Got->getSize(); case R_TLSLD_PC: @@ -637,64 +669,62 @@ static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P, // function as a performance optimization. template <class ELFT, class RelTy> void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { + const unsigned Bits = sizeof(typename ELFT::uint) * 8; + for (const RelTy &Rel : Rels) { - uint32_t Type = Rel.getType(Config->IsMips64EL); + RelType Type = Rel.getType(Config->IsMips64EL); uint64_t Offset = getOffset(Rel.r_offset); uint8_t *BufLoc = Buf + Offset; int64_t Addend = getAddend<ELFT>(Rel); if (!RelTy::IsRela) Addend += Target->getImplicitAddend(BufLoc, Type); - SymbolBody &Sym = this->getFile<ELFT>()->getRelocTargetSym(Rel); + Symbol &Sym = this->getFile<ELFT>()->getRelocTargetSym(Rel); RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc); if (Expr == R_NONE) continue; if (Expr != R_ABS) { - error(this->getLocation<ELFT>(Offset) + ": has non-ABS reloc"); + // GCC 8.0 or earlier have a bug that it emits R_386_GOTPC relocations + // against _GLOBAL_OFFSET_TABLE for .debug_info. The bug seems to have + // been fixed in 2017: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82630, + // but we need to keep this bug-compatible code for a while. + if (Config->EMachine == EM_386 && Type == R_386_GOTPC) + continue; + + error(this->getLocation<ELFT>(Offset) + ": has non-ABS relocation " + + toString(Type) + " against symbol '" + toString(Sym) + "'"); return; } - uint64_t AddrLoc = getParent()->Addr + Offset; - uint64_t SymVA = 0; - if (!Sym.isTls() || Out::TlsPhdr) - SymVA = SignExtend64<sizeof(typename ELFT::uint) * 8>( - getRelocTargetVA(Type, Addend, AddrLoc, Sym, R_ABS)); - Target->relocateOne(BufLoc, Type, SymVA); + if (Sym.isTls() && !Out::TlsPhdr) + Target->relocateOne(BufLoc, Type, 0); + else + Target->relocateOne(BufLoc, Type, SignExtend64<Bits>(Sym.getVA(Addend))); } } -template <class ELFT> elf::ObjectFile<ELFT> *InputSectionBase::getFile() const { - return cast_or_null<elf::ObjectFile<ELFT>>(File); -} - template <class ELFT> void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { - if (Flags & SHF_ALLOC) + if (Flags & SHF_ALLOC) { relocateAlloc(Buf, BufEnd); - else - relocateNonAlloc<ELFT>(Buf, BufEnd); -} + return; + } -template <class ELFT> -void InputSectionBase::relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd) { - // scanReloc function in Writer.cpp constructs Relocations - // vector only for SHF_ALLOC'ed sections. For other sections, - // we handle relocations directly here. - auto *IS = cast<InputSection>(this); - assert(!(IS->Flags & SHF_ALLOC)); - if (IS->AreRelocsRela) - IS->relocateNonAlloc<ELFT>(Buf, IS->template relas<ELFT>()); + auto *Sec = cast<InputSection>(this); + if (Sec->AreRelocsRela) + Sec->relocateNonAlloc<ELFT>(Buf, Sec->template relas<ELFT>()); else - IS->relocateNonAlloc<ELFT>(Buf, IS->template rels<ELFT>()); + Sec->relocateNonAlloc<ELFT>(Buf, Sec->template rels<ELFT>()); } void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { assert(Flags & SHF_ALLOC); const unsigned Bits = Config->Wordsize * 8; + for (const Relocation &Rel : Relocations) { uint64_t Offset = getOffset(Rel.Offset); uint8_t *BufLoc = Buf + Offset; - uint32_t Type = Rel.Type; + RelType Type = Rel.Type; uint64_t AddrLoc = getOutputSection()->Addr + Offset; RelExpr Expr = Rel.Expr; @@ -776,24 +806,15 @@ void InputSection::replace(InputSection *Other) { } template <class ELFT> -EhInputSection::EhInputSection(elf::ObjectFile<ELFT> *F, +EhInputSection::EhInputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, StringRef Name) - : InputSectionBase(F, Header, Name, InputSectionBase::EHFrame) { - // Mark .eh_frame sections as live by default because there are - // usually no relocations that point to .eh_frames. Otherwise, - // the garbage collector would drop all .eh_frame sections. - this->Live = true; -} + : InputSectionBase(F, Header, Name, InputSectionBase::EHFrame) {} SyntheticSection *EhInputSection::getParent() const { return cast_or_null<SyntheticSection>(Parent); } -bool EhInputSection::classof(const SectionBase *S) { - return S->kind() == InputSectionBase::EHFrame; -} - // Returns the index of the first relocation that points to a region between // Begin and Begin+Size. template <class IntTy, class RelTy> @@ -820,14 +841,10 @@ template <class ELFT> void EhInputSection::split() { if (!this->Pieces.empty()) return; - if (this->NumRelocations) { - if (this->AreRelocsRela) - split<ELFT>(this->relas<ELFT>()); - else - split<ELFT>(this->rels<ELFT>()); - return; - } - split<ELFT>(makeArrayRef<typename ELFT::Rela>(nullptr, nullptr)); + if (this->AreRelocsRela) + split<ELFT>(this->relas<ELFT>()); + else + split<ELFT>(this->rels<ELFT>()); } template <class ELFT, class RelTy> @@ -835,7 +852,7 @@ void EhInputSection::split(ArrayRef<RelTy> Rels) { ArrayRef<uint8_t> Data = this->Data; unsigned RelI = 0; for (size_t Off = 0, End = Data.size(); Off != End;) { - size_t Size = readEhRecordSize<ELFT>(this, Off); + size_t Size = readEhRecordSize(this, Off); this->Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI)); // The empty record is the end marker. if (Size == 4) @@ -844,9 +861,8 @@ void EhInputSection::split(ArrayRef<RelTy> Rels) { } } -static size_t findNull(ArrayRef<uint8_t> A, size_t EntSize) { +static size_t findNull(StringRef S, size_t EntSize) { // Optimize the common case. - StringRef S((const char *)A.data(), A.size()); if (EntSize == 1) return S.find(0); @@ -867,14 +883,16 @@ SyntheticSection *MergeInputSection::getParent() const { void MergeInputSection::splitStrings(ArrayRef<uint8_t> Data, size_t EntSize) { size_t Off = 0; bool IsAlloc = this->Flags & SHF_ALLOC; - while (!Data.empty()) { - size_t End = findNull(Data, EntSize); + StringRef S = toStringRef(Data); + + while (!S.empty()) { + size_t End = findNull(S, EntSize); if (End == StringRef::npos) fatal(toString(this) + ": string is not null terminated"); size_t Size = End + EntSize; - Pieces.emplace_back(Off, !IsAlloc); - Hashes.push_back(hash_value(toStringRef(Data.slice(0, Size)))); - Data = Data.slice(Size); + + Pieces.emplace_back(Off, xxHash64(S.substr(0, Size)), !IsAlloc); + S = S.substr(Size); Off += Size; } } @@ -886,41 +904,43 @@ void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> Data, size_t Size = Data.size(); assert((Size % EntSize) == 0); bool IsAlloc = this->Flags & SHF_ALLOC; - for (unsigned I = 0, N = Size; I != N; I += EntSize) { - Hashes.push_back(hash_value(toStringRef(Data.slice(I, EntSize)))); - Pieces.emplace_back(I, !IsAlloc); - } + + for (size_t I = 0; I != Size; I += EntSize) + Pieces.emplace_back(I, xxHash64(toStringRef(Data.slice(I, EntSize))), + !IsAlloc); } template <class ELFT> -MergeInputSection::MergeInputSection(elf::ObjectFile<ELFT> *F, +MergeInputSection::MergeInputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, StringRef Name) - : InputSectionBase(F, Header, Name, InputSectionBase::Merge) {} + : InputSectionBase(F, Header, Name, InputSectionBase::Merge) { + // In order to reduce memory allocation, we assume that mergeable + // sections are smaller than 4 GiB, which is not an unreasonable + // assumption as of 2017. + if (Data.size() > UINT32_MAX) + error(toString(this) + ": section too large"); +} // This function is called after we obtain a complete list of input sections // that need to be linked. This is responsible to split section contents // into small chunks for further processing. // -// Note that this function is called from parallel_for_each. This must be +// Note that this function is called from parallelForEach. This must be // thread-safe (i.e. no memory allocation from the pools). void MergeInputSection::splitIntoPieces() { - ArrayRef<uint8_t> Data = this->Data; - uint64_t EntSize = this->Entsize; + assert(Pieces.empty()); + if (this->Flags & SHF_STRINGS) - splitStrings(Data, EntSize); + splitStrings(Data, Entsize); else - splitNonStrings(Data, EntSize); + splitNonStrings(Data, Entsize); if (Config->GcSections && (this->Flags & SHF_ALLOC)) for (uint64_t Off : LiveOffsets) this->getSectionPiece(Off)->Live = true; } -bool MergeInputSection::classof(const SectionBase *S) { - return S->kind() == InputSectionBase::Merge; -} - // Do binary search to get a section piece at a given input offset. SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) { auto *This = static_cast<const MergeInputSection *>(this); @@ -941,8 +961,7 @@ static It fastUpperBound(It First, It Last, const T &Value, Compare Comp) { } const SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) const { - uint64_t Size = this->Data.size(); - if (Offset >= Size) + if (Data.size() <= Offset) fatal(toString(this) + ": entry is past the end of the section"); // Find the element this offset points to. @@ -957,20 +976,20 @@ const SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) const { // Because contents of a mergeable section is not contiguous in output, // it is not just an addition to a base output offset. uint64_t MergeInputSection::getOffset(uint64_t Offset) const { + if (!Live) + return 0; + // Initialize OffsetMap lazily. llvm::call_once(InitOffsetMap, [&] { OffsetMap.reserve(Pieces.size()); - for (const SectionPiece &Piece : Pieces) - OffsetMap[Piece.InputOff] = Piece.OutputOff; + for (size_t I = 0; I < Pieces.size(); ++I) + OffsetMap[Pieces[I].InputOff] = I; }); // Find a string starting at a given offset. auto It = OffsetMap.find(Offset); if (It != OffsetMap.end()) - return It->second; - - if (!this->Live) - return 0; + return Pieces[It->second].OutputOff; // If Offset is not at beginning of a section piece, it is not in the map. // In that case we need to search from the original section piece vector. @@ -982,56 +1001,50 @@ uint64_t MergeInputSection::getOffset(uint64_t Offset) const { return Piece.OutputOff + Addend; } -template InputSection::InputSection(elf::ObjectFile<ELF32LE> *, - const ELF32LE::Shdr *, StringRef); -template InputSection::InputSection(elf::ObjectFile<ELF32BE> *, - const ELF32BE::Shdr *, StringRef); -template InputSection::InputSection(elf::ObjectFile<ELF64LE> *, - const ELF64LE::Shdr *, StringRef); -template InputSection::InputSection(elf::ObjectFile<ELF64BE> *, - const ELF64BE::Shdr *, StringRef); +template InputSection::InputSection(ObjFile<ELF32LE> *, const ELF32LE::Shdr *, + StringRef); +template InputSection::InputSection(ObjFile<ELF32BE> *, const ELF32BE::Shdr *, + StringRef); +template InputSection::InputSection(ObjFile<ELF64LE> *, const ELF64LE::Shdr *, + StringRef); +template InputSection::InputSection(ObjFile<ELF64BE> *, const ELF64BE::Shdr *, + StringRef); template std::string InputSectionBase::getLocation<ELF32LE>(uint64_t); template std::string InputSectionBase::getLocation<ELF32BE>(uint64_t); template std::string InputSectionBase::getLocation<ELF64LE>(uint64_t); template std::string InputSectionBase::getLocation<ELF64BE>(uint64_t); -template std::string InputSectionBase::getSrcMsg<ELF32LE>(uint64_t); -template std::string InputSectionBase::getSrcMsg<ELF32BE>(uint64_t); -template std::string InputSectionBase::getSrcMsg<ELF64LE>(uint64_t); -template std::string InputSectionBase::getSrcMsg<ELF64BE>(uint64_t); - -template std::string InputSectionBase::getObjMsg<ELF32LE>(uint64_t); -template std::string InputSectionBase::getObjMsg<ELF32BE>(uint64_t); -template std::string InputSectionBase::getObjMsg<ELF64LE>(uint64_t); -template std::string InputSectionBase::getObjMsg<ELF64BE>(uint64_t); +template std::string InputSectionBase::getSrcMsg<ELF32LE>(const Symbol &, + uint64_t); +template std::string InputSectionBase::getSrcMsg<ELF32BE>(const Symbol &, + uint64_t); +template std::string InputSectionBase::getSrcMsg<ELF64LE>(const Symbol &, + uint64_t); +template std::string InputSectionBase::getSrcMsg<ELF64BE>(const Symbol &, + uint64_t); template void InputSection::writeTo<ELF32LE>(uint8_t *); template void InputSection::writeTo<ELF32BE>(uint8_t *); template void InputSection::writeTo<ELF64LE>(uint8_t *); template void InputSection::writeTo<ELF64BE>(uint8_t *); -template elf::ObjectFile<ELF32LE> *InputSectionBase::getFile<ELF32LE>() const; -template elf::ObjectFile<ELF32BE> *InputSectionBase::getFile<ELF32BE>() const; -template elf::ObjectFile<ELF64LE> *InputSectionBase::getFile<ELF64LE>() const; -template elf::ObjectFile<ELF64BE> *InputSectionBase::getFile<ELF64BE>() const; - -template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF32LE> *, +template MergeInputSection::MergeInputSection(ObjFile<ELF32LE> *, const ELF32LE::Shdr *, StringRef); -template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF32BE> *, +template MergeInputSection::MergeInputSection(ObjFile<ELF32BE> *, const ELF32BE::Shdr *, StringRef); -template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF64LE> *, +template MergeInputSection::MergeInputSection(ObjFile<ELF64LE> *, const ELF64LE::Shdr *, StringRef); -template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF64BE> *, +template MergeInputSection::MergeInputSection(ObjFile<ELF64BE> *, const ELF64BE::Shdr *, StringRef); -template EhInputSection::EhInputSection(elf::ObjectFile<ELF32LE> *, +template EhInputSection::EhInputSection(ObjFile<ELF32LE> *, const ELF32LE::Shdr *, StringRef); -template EhInputSection::EhInputSection(elf::ObjectFile<ELF32BE> *, +template EhInputSection::EhInputSection(ObjFile<ELF32BE> *, const ELF32BE::Shdr *, StringRef); -template EhInputSection::EhInputSection(elf::ObjectFile<ELF64LE> *, +template EhInputSection::EhInputSection(ObjFile<ELF64LE> *, const ELF64LE::Shdr *, StringRef); -template EhInputSection::EhInputSection(elf::ObjectFile<ELF64BE> *, +template EhInputSection::EhInputSection(ObjFile<ELF64BE> *, const ELF64BE::Shdr *, StringRef); template void EhInputSection::split<ELF32LE>(); diff --git a/ELF/InputSection.h b/ELF/InputSection.h index d262b589219a..dfd78a8fb458 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -13,7 +13,7 @@ #include "Config.h" #include "Relocations.h" #include "Thunks.h" -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/TinyPtrVector.h" @@ -24,15 +24,13 @@ namespace lld { namespace elf { -class DefinedCommon; -class SymbolBody; +class Symbol; struct SectionPiece; -class DefinedRegular; +class Defined; class SyntheticSection; -template <class ELFT> class EhFrameSection; class MergeSyntheticSection; -template <class ELFT> class ObjectFile; +template <class ELFT> class ObjFile; class OutputSection; // This is the base class of all sections that lld handles. Some are sections in @@ -47,6 +45,13 @@ public: StringRef Name; + // This pointer points to the "real" instance of this instance. + // Usually Repl == this. However, if ICF merges two sections, + // Repl pointer of one section points to another section. So, + // if you need to get a pointer to this instance, do not use + // this but instead this->Repl. + SectionBase *Repl; + unsigned SectionKind : 3; // The next two bit fields are only used by InputSectionBase, but we @@ -54,12 +59,12 @@ public: // The garbage collector sets sections' Live bits. // If GC is disabled, all sections are considered live by default. - unsigned Live : 1; // for garbage collection - unsigned Assigned : 1; // for linker script + unsigned Live : 1; - uint32_t Alignment; + unsigned Bss : 1; // These corresponds to the fields in Elf_Shdr. + uint32_t Alignment; uint64_t Flags; uint64_t Entsize; uint32_t Type; @@ -75,45 +80,20 @@ public: // section. uint64_t getOffset(uint64_t Offset) const; - uint64_t getOffset(const DefinedRegular &Sym) const; - protected: SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags, uint64_t Entsize, uint64_t Alignment, uint32_t Type, uint32_t Info, uint32_t Link) - : Name(Name), SectionKind(SectionKind), Alignment(Alignment), - Flags(Flags), Entsize(Entsize), Type(Type), Link(Link), Info(Info) { - Live = false; - Assigned = false; - } + : Name(Name), Repl(this), SectionKind(SectionKind), Live(false), + Bss(false), Alignment(Alignment), Flags(Flags), Entsize(Entsize), + Type(Type), Link(Link), Info(Info) {} }; // This corresponds to a section of an input file. class InputSectionBase : public SectionBase { public: - static bool classof(const SectionBase *S); - - // The file this section is from. - InputFile *File; - - ArrayRef<uint8_t> Data; - uint64_t getOffsetInFile() const; - - static InputSectionBase Discarded; - - InputSectionBase() - : SectionBase(Regular, "", /*Flags*/ 0, /*Entsize*/ 0, /*Alignment*/ 0, - /*Type*/ 0, - /*Info*/ 0, /*Link*/ 0), - Repl(this) { - Live = false; - Assigned = false; - NumRelocations = 0; - AreRelocsRela = false; - } - template <class ELFT> - InputSectionBase(ObjectFile<ELFT> *File, const typename ELFT::Shdr *Header, + InputSectionBase(ObjFile<ELFT> *File, const typename ELFT::Shdr *Header, StringRef Name, Kind SectionKind); InputSectionBase(InputFile *File, uint64_t Flags, uint32_t Type, @@ -121,6 +101,33 @@ public: uint32_t Alignment, ArrayRef<uint8_t> Data, StringRef Name, Kind SectionKind); + static bool classof(const SectionBase *S) { return S->kind() != Output; } + + // The file which contains this section. It's dynamic type is always + // ObjFile<ELFT>, but in order to avoid ELFT, we use InputFile as + // its static type. + InputFile *File; + + template <class ELFT> ObjFile<ELFT> *getFile() const { + return cast_or_null<ObjFile<ELFT>>(File); + } + + ArrayRef<uint8_t> Data; + uint64_t getOffsetInFile() const; + + // True if this section has already been placed to a linker script + // output section. This is needed because, in a linker script, you + // can refer to the same section more than once. For example, in + // the following linker script, + // + // .foo : { *(.text) } + // .bar : { *(.text) } + // + // .foo takes all .text sections, and .bar becomes empty. To achieve + // this, we need to memorize whether a section has been placed or + // not for each input section. + bool Assigned = false; + // Input sections are part of an output section. Special sections // like .eh_frame and merge sections are first combined into a // synthetic section that is then added to an output section. In all @@ -131,12 +138,14 @@ public: const void *FirstRelocation = nullptr; unsigned NumRelocations : 31; unsigned AreRelocsRela : 1; + template <class ELFT> ArrayRef<typename ELFT::Rel> rels() const { assert(!AreRelocsRela); return llvm::makeArrayRef( static_cast<const typename ELFT::Rel *>(FirstRelocation), NumRelocations); } + template <class ELFT> ArrayRef<typename ELFT::Rela> relas() const { assert(AreRelocsRela); return llvm::makeArrayRef( @@ -144,38 +153,34 @@ public: NumRelocations); } - // This pointer points to the "real" instance of this instance. - // Usually Repl == this. However, if ICF merges two sections, - // Repl pointer of one section points to another section. So, - // if you need to get a pointer to this instance, do not use - // this but instead this->Repl. - InputSectionBase *Repl; - // InputSections that are dependent on us (reverse dependency for GC) - llvm::TinyPtrVector<InputSectionBase *> DependentSections; + llvm::TinyPtrVector<InputSection *> DependentSections; // Returns the size of this section (even if this is a common or BSS.) size_t getSize() const; - template <class ELFT> ObjectFile<ELFT> *getFile() const; - - template <class ELFT> llvm::object::ELFFile<ELFT> getObj() const { - return getFile<ELFT>()->getObj(); - } - InputSection *getLinkOrderDep() const; - void uncompress(); + // Compilers emit zlib-compressed debug sections if the -gz option + // is given. This function checks if this section is compressed, and + // if so, decompress in memory. + void maybeUncompress(); // Returns a source location string. Used to construct an error message. template <class ELFT> std::string getLocation(uint64_t Offset); - template <class ELFT> std::string getSrcMsg(uint64_t Offset); - template <class ELFT> std::string getObjMsg(uint64_t Offset); + template <class ELFT> + std::string getSrcMsg(const Symbol &Sym, uint64_t Offset); + std::string getObjMsg(uint64_t Offset); + // Each section knows how to relocate itself. These functions apply + // relocations, assuming that Buf points to this section's copy in + // the mmap'ed output buffer. template <class ELFT> void relocate(uint8_t *Buf, uint8_t *BufEnd); void relocateAlloc(uint8_t *Buf, uint8_t *BufEnd); - template <class ELFT> void relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd); + // The native ELF reloc data type is not very convenient to handle. + // So we convert ELF reloc records to our own records in Relocations.cpp. + // This vector contains such "cooked" relocations. std::vector<Relocation> Relocations; template <typename T> llvm::ArrayRef<T> getDataAs() const { @@ -183,36 +188,43 @@ public: assert(S % sizeof(T) == 0); return llvm::makeArrayRef<T>((const T *)Data.data(), S / sizeof(T)); } + +private: + // A pointer that owns uncompressed data if a section is compressed by zlib. + // Since the feature is not used often, this is usually a nullptr. + std::unique_ptr<char[]> UncompressBuf; }; // SectionPiece represents a piece of splittable section contents. // We allocate a lot of these and binary search on them. This means that they // have to be as compact as possible, which is why we don't store the size (can -// be found by looking at the next one) and put the hash in a side table. +// be found by looking at the next one). struct SectionPiece { - SectionPiece(size_t Off, bool Live = false) - : InputOff(Off), OutputOff(-1), Live(Live || !Config->GcSections) {} - - size_t InputOff; - ssize_t OutputOff : 8 * sizeof(ssize_t) - 1; - size_t Live : 1; + SectionPiece(size_t Off, uint32_t Hash, bool Live) + : InputOff(Off), Hash(Hash), OutputOff(-1), + Live(Live || !Config->GcSections) {} + + uint32_t InputOff; + uint32_t Hash; + int64_t OutputOff : 63; + uint64_t Live : 1; }; -static_assert(sizeof(SectionPiece) == 2 * sizeof(size_t), - "SectionPiece is too big"); + +static_assert(sizeof(SectionPiece) == 16, "SectionPiece is too big"); // This corresponds to a SHF_MERGE section of an input file. class MergeInputSection : public InputSectionBase { public: template <class ELFT> - MergeInputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header, + MergeInputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, StringRef Name); - static bool classof(const SectionBase *S); + static bool classof(const SectionBase *S) { return S->kind() == Merge; } void splitIntoPieces(); // Mark the piece at a given offset live. Used by GC. void markLiveAt(uint64_t Offset) { - assert(this->Flags & llvm::ELF::SHF_ALLOC); - LiveOffsets.insert(Offset); + if (this->Flags & llvm::ELF::SHF_ALLOC) + LiveOffsets.insert(Offset); } // Translate an offset in the input section to an offset @@ -228,14 +240,9 @@ public: LLVM_ATTRIBUTE_ALWAYS_INLINE llvm::CachedHashStringRef getData(size_t I) const { size_t Begin = Pieces[I].InputOff; - size_t End; - if (Pieces.size() - 1 == I) - End = this->Data.size(); - else - End = Pieces[I + 1].InputOff; - - StringRef S = {(const char *)(this->Data.data() + Begin), End - Begin}; - return {S, Hashes[I]}; + size_t End = + (Pieces.size() - 1 == I) ? Data.size() : Pieces[I + 1].InputOff; + return {toStringRef(Data.slice(Begin, End - Begin)), Pieces[I].Hash}; } // Returns the SectionPiece at a given input section offset. @@ -248,24 +255,23 @@ private: void splitStrings(ArrayRef<uint8_t> A, size_t Size); void splitNonStrings(ArrayRef<uint8_t> A, size_t Size); - std::vector<uint32_t> Hashes; - - mutable llvm::DenseMap<uint64_t, uint64_t> OffsetMap; + mutable llvm::DenseMap<uint32_t, uint32_t> OffsetMap; mutable llvm::once_flag InitOffsetMap; llvm::DenseSet<uint64_t> LiveOffsets; }; -struct EhSectionPiece : public SectionPiece { - EhSectionPiece(size_t Off, InputSectionBase *ID, uint32_t Size, +struct EhSectionPiece { + EhSectionPiece(size_t Off, InputSectionBase *Sec, uint32_t Size, unsigned FirstRelocation) - : SectionPiece(Off, false), ID(ID), Size(Size), - FirstRelocation(FirstRelocation) {} - InputSectionBase *ID; - uint32_t Size; - uint32_t size() const { return Size; } + : InputOff(Off), Sec(Sec), Size(Size), FirstRelocation(FirstRelocation) {} - ArrayRef<uint8_t> data() { return {ID->Data.data() + this->InputOff, Size}; } + ArrayRef<uint8_t> data() { return {Sec->Data.data() + this->InputOff, Size}; } + + size_t InputOff; + ssize_t OutputOff = -1; + InputSectionBase *Sec; + uint32_t Size; unsigned FirstRelocation; }; @@ -273,9 +279,9 @@ struct EhSectionPiece : public SectionPiece { class EhInputSection : public InputSectionBase { public: template <class ELFT> - EhInputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header, + EhInputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, StringRef Name); - static bool classof(const SectionBase *S); + static bool classof(const SectionBase *S) { return S->kind() == EHFrame; } template <class ELFT> void split(); template <class ELFT, class RelTy> void split(ArrayRef<RelTy> Rels); @@ -295,7 +301,7 @@ public: InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, ArrayRef<uint8_t> Data, StringRef Name, Kind K = Regular); template <class ELFT> - InputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header, + InputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, StringRef Name); // Write this section to a mmap'ed file, assuming Buf is pointing to @@ -304,8 +310,10 @@ public: OutputSection *getParent() const; - // The offset from beginning of the output sections this section was assigned - // to. The writer sets a value. + // This variable has two usages. Initially, it represents an index in the + // OutputSection's InputSection list, and is used when ordering SHF_LINK_ORDER + // sections. After assignAddresses is called, it represents the offset from + // the beginning of the output section this section was assigned to. uint64_t OutSecOff = 0; static bool classof(const SectionBase *S); @@ -321,6 +329,8 @@ public: // Called by ICF to merge two input sections. void replace(InputSection *Other); + static InputSection Discarded; + private: template <class ELFT, class RelTy> void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); @@ -331,6 +341,9 @@ private: // The list of all input sections. extern std::vector<InputSectionBase *> InputSections; +// Builds section order for handling --symbol-ordering-file. +llvm::DenseMap<SectionBase *, int> buildSectionOrder(); + } // namespace elf std::string toString(const elf::InputSectionBase *); diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp index 3a536271db4c..bfd85288d186 100644 --- a/ELF/LTO.cpp +++ b/ELF/LTO.cpp @@ -9,10 +9,12 @@ #include "LTO.h" #include "Config.h" -#include "Error.h" #include "InputFiles.h" +#include "LinkerScript.h" +#include "SymbolTable.h" #include "Symbols.h" -#include "lld/Core/TargetOptionsCommandFlags.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/TargetOptionsCommandFlags.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" @@ -60,10 +62,8 @@ static void diagnosticHandler(const DiagnosticInfo &DI) { } static void checkError(Error E) { - handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) -> Error { - error(EIB.message()); - return Error::success(); - }); + handleAllErrors(std::move(E), + [&](ErrorInfoBase &EIB) { error(EIB.message()); }); } static std::unique_ptr<lto::LTO> createLTO() { @@ -73,6 +73,10 @@ static std::unique_ptr<lto::LTO> createLTO() { Conf.Options = InitTargetOptionsFromCodeGenFlags(); Conf.Options.RelaxELFRelocations = true; + // Always emit a section per function/datum with LTO. + Conf.Options.FunctionSections = true; + Conf.Options.DataSections = true; + if (Config->Relocatable) Conf.RelocModel = None; else if (Config->Pic) @@ -103,13 +107,20 @@ static std::unique_ptr<lto::LTO> createLTO() { Config->LTOPartitions); } -BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {} +BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) { + for (Symbol *Sym : Symtab->getSymbols()) { + StringRef Name = Sym->getName(); + for (StringRef Prefix : {"__start_", "__stop_"}) + if (Name.startswith(Prefix)) + UsedStartStop.insert(Name.substr(Prefix.size())); + } +} BitcodeCompiler::~BitcodeCompiler() = default; static void undefine(Symbol *S) { - replaceBody<Undefined>(S, S->body()->getName(), /*IsLocal=*/false, - STV_DEFAULT, S->body()->Type, nullptr); + replaceSymbol<Undefined>(S, nullptr, S->getName(), STB_GLOBAL, STV_DEFAULT, + S->Type); } void BitcodeCompiler::add(BitcodeFile &F) { @@ -118,25 +129,42 @@ void BitcodeCompiler::add(BitcodeFile &F) { std::vector<Symbol *> Syms = F.getSymbols(); std::vector<lto::SymbolResolution> Resols(Syms.size()); + DenseSet<StringRef> ScriptSymbols; + for (BaseCommand *Base : Script->SectionCommands) + if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) + ScriptSymbols.insert(Cmd->Name); + // Provide a resolution to the LTO API for each symbol. for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) { Symbol *Sym = Syms[SymNum]; lto::SymbolResolution &R = Resols[SymNum]; ++SymNum; - SymbolBody *B = Sym->body(); // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile // reports two symbols for module ASM defined. Without this check, lld // flags an undefined in IR with a definition in ASM as prevailing. // Once IRObjectFile is fixed to report only one symbol this hack can // be removed. - R.Prevailing = !ObjSym.isUndefined() && B->File == &F; - - R.VisibleToRegularObj = - Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym()); + R.Prevailing = !ObjSym.isUndefined() && Sym->File == &F; + + // We ask LTO to preserve following global symbols: + // 1) All symbols when doing relocatable link, so that them can be used + // for doing final link. + // 2) Symbols that are used in regular objects. + // 3) C named sections if we have corresponding __start_/__stop_ symbol. + // 4) Symbols that are defined in bitcode files and used for dynamic linking. + R.VisibleToRegularObj = Config->Relocatable || Sym->IsUsedInRegularObj || + (R.Prevailing && Sym->includeInDynsym()) || + UsedStartStop.count(ObjSym.getSectionName()); if (R.Prevailing) undefine(Sym); - R.LinkerRedefined = Config->RenamedSymbols.count(Sym); + + // We tell LTO to not apply interprocedural optimization for following + // symbols because otherwise LTO would inline them while their values are + // still not final: + // 1) Aliased (with --defsym) or wrapped (with --wrap) symbols. + // 2) Symbols redefined in linker script. + R.LinkerRedefined = !Sym->CanInline || ScriptSymbols.count(Sym->getName()); } checkError(LTOObj->add(std::move(F.Obj), Resols)); } @@ -156,9 +184,8 @@ std::vector<InputFile *> BitcodeCompiler::compile() { if (!Config->ThinLTOCacheDir.empty()) Cache = check( lto::localCache(Config->ThinLTOCacheDir, - [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) { - Files[Task] = std::move(MB); - })); + [&](size_t Task, std::unique_ptr<MemoryBuffer> MB, + StringRef Path) { Files[Task] = std::move(MB); })); checkError(LTOObj->run( [&](size_t Task) { diff --git a/ELF/LTO.h b/ELF/LTO.h index d19923c90a99..223af507a97d 100644 --- a/ELF/LTO.h +++ b/ELF/LTO.h @@ -21,7 +21,8 @@ #ifndef LLD_ELF_LTO_H #define LLD_ELF_LTO_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallString.h" #include <memory> #include <vector> @@ -50,6 +51,7 @@ private: std::unique_ptr<llvm::lto::LTO> LTOObj; std::vector<SmallString<0>> Buff; std::vector<std::unique_ptr<MemoryBuffer>> Files; + llvm::DenseSet<StringRef> UsedStartStop; }; } // namespace elf } // namespace lld diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index 8bdbd8db20ad..91873e318f54 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -14,20 +14,19 @@ #include "LinkerScript.h" #include "Config.h" #include "InputSection.h" -#include "Memory.h" #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" -#include "Threads.h" #include "Writer.h" +#include "lld/Common/Memory.h" +#include "lld/Common/Threads.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" @@ -50,62 +49,56 @@ using namespace lld::elf; LinkerScript *elf::Script; +static uint64_t getOutputSectionVA(SectionBase *InputSec, StringRef Loc) { + if (OutputSection *OS = InputSec->getOutputSection()) + return OS->Addr; + error(Loc + ": unable to evaluate expression: input section " + + InputSec->Name + " has no output section assigned"); + return 0; +} + uint64_t ExprValue::getValue() const { - if (Sec) { - if (OutputSection *OS = Sec->getOutputSection()) - return alignTo(Sec->getOffset(Val) + OS->Addr, Alignment); - error(Loc + ": unable to evaluate expression: input section " + Sec->Name + - " has no output section assigned"); - } + if (Sec) + return alignTo(Sec->getOffset(Val) + getOutputSectionVA(Sec, Loc), + Alignment); return alignTo(Val, Alignment); } uint64_t ExprValue::getSecAddr() const { if (Sec) - return Sec->getOffset(0) + Sec->getOutputSection()->Addr; + return Sec->getOffset(0) + getOutputSectionVA(Sec, Loc); return 0; } -template <class ELFT> static SymbolBody *addRegular(SymbolAssignment *Cmd) { - Symbol *Sym; - uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; - std::tie(Sym, std::ignore) = Symtab<ELFT>::X->insert( - Cmd->Name, /*Type*/ 0, Visibility, /*CanOmitFromDynSym*/ false, - /*File*/ nullptr); - Sym->Binding = STB_GLOBAL; - ExprValue Value = Cmd->Expression(); - SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec; - - // We want to set symbol values early if we can. This allows us to use symbols - // as variables in linker scripts. Doing so allows us to write expressions - // like this: `alignment = 16; . = ALIGN(., alignment)` - uint64_t SymValue = Value.isAbsolute() ? Value.getValue() : 0; - replaceBody<DefinedRegular>(Sym, Cmd->Name, /*IsLocal=*/false, Visibility, - STT_NOTYPE, SymValue, 0, Sec, nullptr); - return Sym->body(); +uint64_t ExprValue::getSectionOffset() const { + // If the alignment is trivial, we don't have to compute the full + // value to know the offset. This allows this function to succeed in + // cases where the output section is not yet known. + if (Alignment == 1) + return Val; + return getValue() - getSecAddr(); } -OutputSectionCommand * -LinkerScript::createOutputSectionCommand(StringRef Name, StringRef Location) { - OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name]; - OutputSectionCommand *Cmd; - if (CmdRef && CmdRef->Location.empty()) { +OutputSection *LinkerScript::createOutputSection(StringRef Name, + StringRef Location) { + OutputSection *&SecRef = NameToOutputSection[Name]; + OutputSection *Sec; + if (SecRef && SecRef->Location.empty()) { // There was a forward reference. - Cmd = CmdRef; + Sec = SecRef; } else { - Cmd = make<OutputSectionCommand>(Name); - if (!CmdRef) - CmdRef = Cmd; + Sec = make<OutputSection>(Name, SHT_NOBITS, 0); + if (!SecRef) + SecRef = Sec; } - Cmd->Location = Location; - return Cmd; + Sec->Location = Location; + return Sec; } -OutputSectionCommand * -LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) { - OutputSectionCommand *&CmdRef = NameToOutputSectionCommand[Name]; +OutputSection *LinkerScript::getOrCreateOutputSection(StringRef Name) { + OutputSection *&CmdRef = NameToOutputSection[Name]; if (!CmdRef) - CmdRef = make<OutputSectionCommand>(Name); + CmdRef = make<OutputSection>(Name, SHT_PROGBITS, 0); return CmdRef; } @@ -113,16 +106,56 @@ void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { uint64_t Val = E().getValue(); if (Val < Dot && InSec) error(Loc + ": unable to move location counter backward for: " + - CurAddressState->OutSec->Name); + Ctx->OutSec->Name); Dot = Val; + // Update to location counter means update to section size. if (InSec) - CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr; + Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr; } -// Sets value of a symbol. Two kinds of symbols are processed: synthetic -// symbols, whose value is an offset from beginning of section and regular -// symbols whose value is absolute. +// This function is called from processSectionCommands, +// while we are fixing the output section layout. +void LinkerScript::addSymbol(SymbolAssignment *Cmd) { + if (Cmd->Name == ".") + return; + + // If a symbol was in PROVIDE(), we need to define it only when + // it is a referenced undefined symbol. + Symbol *B = Symtab->find(Cmd->Name); + if (Cmd->Provide && (!B || B->isDefined())) + return; + + // Define a symbol. + Symbol *Sym; + uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; + std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, /*Type*/ 0, Visibility, + /*CanOmitFromDynSym*/ false, + /*File*/ nullptr); + ExprValue Value = Cmd->Expression(); + SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec; + + // When this function is called, section addresses have not been + // fixed yet. So, we may or may not know the value of the RHS + // expression. + // + // For example, if an expression is `x = 42`, we know x is always 42. + // However, if an expression is `x = .`, there's no way to know its + // value at the moment. + // + // We want to set symbol values early if we can. This allows us to + // use symbols as variables in linker scripts. Doing so allows us to + // write expressions like this: `alignment = 16; . = ALIGN(., alignment)`. + uint64_t SymValue = Value.Sec ? 0 : Value.getValue(); + + replaceSymbol<Defined>(Sym, nullptr, Cmd->Name, STB_GLOBAL, Visibility, + STT_NOTYPE, SymValue, 0, Sec); + Cmd->Sym = cast<Defined>(Sym); +} + +// This function is called from assignAddresses, while we are +// fixing the output section addresses. This function is supposed +// to set the final value for a given symbol assignment. void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) { if (Cmd->Name == ".") { setDot(Cmd->Expression, Cmd->Location, InSec); @@ -132,116 +165,36 @@ void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) { if (!Cmd->Sym) return; - auto *Sym = cast<DefinedRegular>(Cmd->Sym); ExprValue V = Cmd->Expression(); if (V.isAbsolute()) { - Sym->Value = V.getValue(); + Cmd->Sym->Section = nullptr; + Cmd->Sym->Value = V.getValue(); } else { - Sym->Section = V.Sec; - Sym->Value = alignTo(V.Val, V.Alignment); - } -} - -static SymbolBody *findSymbol(StringRef S) { - switch (Config->EKind) { - case ELF32LEKind: - return Symtab<ELF32LE>::X->find(S); - case ELF32BEKind: - return Symtab<ELF32BE>::X->find(S); - case ELF64LEKind: - return Symtab<ELF64LE>::X->find(S); - case ELF64BEKind: - return Symtab<ELF64BE>::X->find(S); - default: - llvm_unreachable("unknown Config->EKind"); + Cmd->Sym->Section = V.Sec; + Cmd->Sym->Value = V.getSectionOffset(); } } -static SymbolBody *addRegularSymbol(SymbolAssignment *Cmd) { - switch (Config->EKind) { - case ELF32LEKind: - return addRegular<ELF32LE>(Cmd); - case ELF32BEKind: - return addRegular<ELF32BE>(Cmd); - case ELF64LEKind: - return addRegular<ELF64LE>(Cmd); - case ELF64BEKind: - return addRegular<ELF64BE>(Cmd); - default: - llvm_unreachable("unknown Config->EKind"); - } -} - -void LinkerScript::addSymbol(SymbolAssignment *Cmd) { - if (Cmd->Name == ".") - return; - - // If a symbol was in PROVIDE(), we need to define it only when - // it is a referenced undefined symbol. - SymbolBody *B = findSymbol(Cmd->Name); - if (Cmd->Provide && (!B || B->isDefined())) - return; - - Cmd->Sym = addRegularSymbol(Cmd); -} - -bool SymbolAssignment::classof(const BaseCommand *C) { - return C->Kind == AssignmentKind; -} - -bool OutputSectionCommand::classof(const BaseCommand *C) { - return C->Kind == OutputSectionKind; -} - -// Fill [Buf, Buf + Size) with Filler. -// This is used for linker script "=fillexp" command. -static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) { - size_t I = 0; - for (; I + 4 < Size; I += 4) - memcpy(Buf + I, &Filler, 4); - memcpy(Buf + I, &Filler, Size - I); -} - -bool InputSectionDescription::classof(const BaseCommand *C) { - return C->Kind == InputSectionKind; -} - -bool AssertCommand::classof(const BaseCommand *C) { - return C->Kind == AssertKind; -} - -bool BytesDataCommand::classof(const BaseCommand *C) { - return C->Kind == BytesDataKind; -} - -static StringRef basename(InputSectionBase *S) { - if (S->File) - return sys::path::filename(S->File->getName()); - return ""; +static std::string getFilename(InputFile *File) { + if (!File) + return ""; + if (File->ArchiveName.empty()) + return File->getName(); + return (File->ArchiveName + "(" + File->getName() + ")").str(); } bool LinkerScript::shouldKeep(InputSectionBase *S) { - for (InputSectionDescription *ID : Opt.KeptSections) - if (ID->FilePat.match(basename(S))) + if (KeptSections.empty()) + return false; + std::string Filename = getFilename(S->File); + for (InputSectionDescription *ID : KeptSections) + if (ID->FilePat.match(Filename)) for (SectionPattern &P : ID->SectionPatterns) if (P.SectionPat.match(S->Name)) return true; return false; } -// If an input string is in the form of "foo.N" where N is a number, -// return N. Otherwise, returns 65536, which is one greater than the -// lowest priority. -static int getPriority(StringRef S) { - size_t Pos = S.rfind('.'); - if (Pos == StringRef::npos) - return 65536; - int V; - if (!to_integer(S.substr(Pos + 1), V, 10)) - return 65536; - return V; -} - // A helper function for the SORT() command. static std::function<bool(InputSectionBase *, InputSectionBase *)> getComparator(SortSectionPolicy K) { @@ -267,28 +220,63 @@ getComparator(SortSectionPolicy K) { } // A helper function for the SORT() command. -static bool matchConstraints(ArrayRef<InputSectionBase *> Sections, +static bool matchConstraints(ArrayRef<InputSection *> Sections, ConstraintKind Kind) { if (Kind == ConstraintKind::NoConstraint) return true; - bool IsRW = llvm::any_of(Sections, [](InputSectionBase *Sec) { - return static_cast<InputSectionBase *>(Sec)->Flags & SHF_WRITE; - }); + bool IsRW = llvm::any_of( + Sections, [](InputSection *Sec) { return Sec->Flags & SHF_WRITE; }); return (IsRW && Kind == ConstraintKind::ReadWrite) || (!IsRW && Kind == ConstraintKind::ReadOnly); } -static void sortSections(InputSection **Begin, InputSection **End, +static void sortSections(MutableArrayRef<InputSection *> Vec, SortSectionPolicy K) { if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None) - std::stable_sort(Begin, End, getComparator(K)); + std::stable_sort(Vec.begin(), Vec.end(), getComparator(K)); +} + +// Sort sections as instructed by SORT-family commands and --sort-section +// option. Because SORT-family commands can be nested at most two depth +// (e.g. SORT_BY_NAME(SORT_BY_ALIGNMENT(.text.*))) and because the command +// line option is respected even if a SORT command is given, the exact +// behavior we have here is a bit complicated. Here are the rules. +// +// 1. If two SORT commands are given, --sort-section is ignored. +// 2. If one SORT command is given, and if it is not SORT_NONE, +// --sort-section is handled as an inner SORT command. +// 3. If one SORT command is given, and if it is SORT_NONE, don't sort. +// 4. If no SORT command is given, sort according to --sort-section. +// 5. If no SORT commands are given and --sort-section is not specified, +// apply sorting provided by --symbol-ordering-file if any exist. +static void sortInputSections( + MutableArrayRef<InputSection *> Vec, const SectionPattern &Pat, + const DenseMap<SectionBase *, int> &Order) { + if (Pat.SortOuter == SortSectionPolicy::None) + return; + + if (Pat.SortOuter == SortSectionPolicy::Default && + Config->SortSection == SortSectionPolicy::Default) { + // If -symbol-ordering-file was given, sort accordingly. + // Usually, Order is empty. + if (!Order.empty()) + sortByOrder(Vec, [&](InputSectionBase *S) { return Order.lookup(S); }); + return; + } + + if (Pat.SortInner == SortSectionPolicy::Default) + sortSections(Vec, Config->SortSection); + else + sortSections(Vec, Pat.SortInner); + sortSections(Vec, Pat.SortOuter); } // Compute and remember which sections the InputSectionDescription matches. std::vector<InputSection *> -LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { +LinkerScript::computeInputSections(const InputSectionDescription *Cmd, + const DenseMap<SectionBase *, int> &Order) { std::vector<InputSection *> Ret; // Collects all sections that satisfy constraints of Cmd. @@ -296,13 +284,8 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { size_t SizeBefore = Ret.size(); for (InputSectionBase *Sec : InputSections) { - if (Sec->Assigned) - continue; - - if (!Sec->Live) { - reportDiscarded(Sec); + if (!Sec->Live || Sec->Assigned) continue; - } // For -emit-relocs we have to ignore entries like // .rela.dyn : { *(.rela.data) } @@ -310,67 +293,51 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) continue; - StringRef Filename = basename(Sec); + std::string Filename = getFilename(Sec->File); if (!Cmd->FilePat.match(Filename) || Pat.ExcludedFilePat.match(Filename) || !Pat.SectionPat.match(Sec->Name)) continue; + // It is safe to assume that Sec is an InputSection + // because mergeable or EH input sections have already been + // handled and eliminated. Ret.push_back(cast<InputSection>(Sec)); Sec->Assigned = true; } - // Sort sections as instructed by SORT-family commands and --sort-section - // option. Because SORT-family commands can be nested at most two depth - // (e.g. SORT_BY_NAME(SORT_BY_ALIGNMENT(.text.*))) and because the command - // line option is respected even if a SORT command is given, the exact - // behavior we have here is a bit complicated. Here are the rules. - // - // 1. If two SORT commands are given, --sort-section is ignored. - // 2. If one SORT command is given, and if it is not SORT_NONE, - // --sort-section is handled as an inner SORT command. - // 3. If one SORT command is given, and if it is SORT_NONE, don't sort. - // 4. If no SORT command is given, sort according to --sort-section. - InputSection **Begin = Ret.data() + SizeBefore; - InputSection **End = Ret.data() + Ret.size(); - if (Pat.SortOuter != SortSectionPolicy::None) { - if (Pat.SortInner == SortSectionPolicy::Default) - sortSections(Begin, End, Config->SortSection); - else - sortSections(Begin, End, Pat.SortInner); - sortSections(Begin, End, Pat.SortOuter); - } + sortInputSections(MutableArrayRef<InputSection *>(Ret).slice(SizeBefore), + Pat, Order); } return Ret; } -void LinkerScript::discard(ArrayRef<InputSectionBase *> V) { - for (InputSectionBase *S : V) { - S->Live = false; +void LinkerScript::discard(ArrayRef<InputSection *> V) { + for (InputSection *S : V) { if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab || S == InX::DynStrTab) error("discarding " + S->Name + " section is not allowed"); + + S->Assigned = false; + S->Live = false; discard(S->DependentSections); } } -std::vector<InputSectionBase *> -LinkerScript::createInputSectionList(OutputSectionCommand &OutCmd) { - std::vector<InputSectionBase *> Ret; - - for (BaseCommand *Base : OutCmd.Commands) { - auto *Cmd = dyn_cast<InputSectionDescription>(Base); - if (!Cmd) - continue; +std::vector<InputSection *> LinkerScript::createInputSectionList( + OutputSection &OutCmd, const DenseMap<SectionBase *, int> &Order) { + std::vector<InputSection *> Ret; - Cmd->Sections = computeInputSections(Cmd); - Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end()); + for (BaseCommand *Base : OutCmd.SectionCommands) { + if (auto *Cmd = dyn_cast<InputSectionDescription>(Base)) { + Cmd->Sections = computeInputSections(Cmd, Order); + Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end()); + } } - return Ret; } -void LinkerScript::processCommands(OutputSectionFactory &Factory) { +void LinkerScript::processSectionCommands() { // A symbol can be assigned before any section is mentioned in the linker // script. In an DSO, the symbol values are addresses, so the only important // section values are: @@ -382,28 +349,31 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { // which will map to whatever the first actual section is. Aether = make<OutputSection>("", 0, SHF_ALLOC); Aether->SectionIndex = 1; - auto State = make_unique<AddressState>(Opt); - // CurAddressState captures the local AddressState and makes it accessible - // deliberately. This is needed as there are some cases where we cannot just + + // Ctx captures the local AddressState and makes it accessible deliberately. + // This is needed as there are some cases where we cannot just // thread the current state through to a lambda function created by the // script parser. - CurAddressState = State.get(); - CurAddressState->OutSec = Aether; - Dot = 0; + auto Deleter = make_unique<AddressState>(); + Ctx = Deleter.get(); + Ctx->OutSec = Aether; - for (size_t I = 0; I < Opt.Commands.size(); ++I) { + size_t I = 0; + DenseMap<SectionBase *, int> Order = buildSectionOrder(); + // Add input sections to output sections. + for (BaseCommand *Base : SectionCommands) { // Handle symbol assignments outside of any output section. - if (auto *Cmd = dyn_cast<SymbolAssignment>(Opt.Commands[I])) { + if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { addSymbol(Cmd); continue; } - if (auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I])) { - std::vector<InputSectionBase *> V = createInputSectionList(*Cmd); + if (auto *Sec = dyn_cast<OutputSection>(Base)) { + std::vector<InputSection *> V = createInputSectionList(*Sec, Order); // The output section name `/DISCARD/' is special. // Any input section assigned to it is discarded. - if (Cmd->Name == "/DISCARD/") { + if (Sec->Name == "/DISCARD/") { discard(V); continue; } @@ -413,250 +383,265 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { // sections satisfy a given constraint. If not, a directive is handled // as if it wasn't present from the beginning. // - // Because we'll iterate over Commands many more times, the easiest - // way to "make it as if it wasn't present" is to just remove it. - if (!matchConstraints(V, Cmd->Constraint)) { + // Because we'll iterate over SectionCommands many more times, the easy + // way to "make it as if it wasn't present" is to make it empty. + if (!matchConstraints(V, Sec->Constraint)) { for (InputSectionBase *S : V) S->Assigned = false; - Opt.Commands.erase(Opt.Commands.begin() + I); - --I; + Sec->SectionCommands.clear(); continue; } // A directive may contain symbol definitions like this: // ".foo : { ...; bar = .; }". Handle them. - for (BaseCommand *Base : Cmd->Commands) + for (BaseCommand *Base : Sec->SectionCommands) if (auto *OutCmd = dyn_cast<SymbolAssignment>(Base)) addSymbol(OutCmd); // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign // is given, input sections are aligned to that value, whether the // given value is larger or smaller than the original section alignment. - if (Cmd->SubalignExpr) { - uint32_t Subalign = Cmd->SubalignExpr().getValue(); + if (Sec->SubalignExpr) { + uint32_t Subalign = Sec->SubalignExpr().getValue(); for (InputSectionBase *S : V) S->Alignment = Subalign; } // Add input sections to an output section. - for (InputSectionBase *S : V) - Factory.addInputSec(S, Cmd->Name, Cmd->Sec); - if (OutputSection *Sec = Cmd->Sec) { - assert(Sec->SectionIndex == INT_MAX); - Sec->SectionIndex = I; - if (Cmd->Noload) - Sec->Type = SHT_NOBITS; - SecToCommand[Sec] = Cmd; - } + for (InputSection *S : V) + Sec->addSection(S); + + Sec->SectionIndex = I++; + if (Sec->Noload) + Sec->Type = SHT_NOBITS; } } - CurAddressState = nullptr; + Ctx = nullptr; } -void LinkerScript::fabricateDefaultCommands() { - std::vector<BaseCommand *> Commands; - - // Define start address - uint64_t StartAddr = -1; - - // The Sections with -T<section> have been sorted in order of ascending - // address. We must lower StartAddr if the lowest -T<section address> as - // calls to setDot() must be monotonically increasing. - for (auto &KV : Config->SectionStartMap) - StartAddr = std::min(StartAddr, KV.second); - - Commands.push_back(make<SymbolAssignment>( - ".", - [=] { - return std::min(StartAddr, Config->ImageBase + elf::getHeaderSize()); - }, - "")); +static OutputSection *findByName(ArrayRef<BaseCommand *> Vec, + StringRef Name) { + for (BaseCommand *Base : Vec) + if (auto *Sec = dyn_cast<OutputSection>(Base)) + if (Sec->Name == Name) + return Sec; + return nullptr; +} - // For each OutputSection that needs a VA fabricate an OutputSectionCommand - // with an InputSectionDescription describing the InputSections - for (OutputSection *Sec : OutputSections) { - auto *OSCmd = createOutputSectionCommand(Sec->Name, "<internal>"); - OSCmd->Sec = Sec; - SecToCommand[Sec] = OSCmd; - - Commands.push_back(OSCmd); - if (Sec->Sections.size()) { - auto *ISD = make<InputSectionDescription>(""); - OSCmd->Commands.push_back(ISD); - for (InputSection *ISec : Sec->Sections) { - ISD->Sections.push_back(ISec); - ISec->Assigned = true; - } +static OutputSection *createSection(InputSectionBase *IS, + StringRef OutsecName) { + OutputSection *Sec = Script->createOutputSection(OutsecName, "<internal>"); + Sec->addSection(cast<InputSection>(IS)); + return Sec; +} + +static OutputSection *addInputSec(StringMap<OutputSection *> &Map, + InputSectionBase *IS, StringRef OutsecName) { + // Sections with SHT_GROUP or SHF_GROUP attributes reach here only when the -r + // option is given. A section with SHT_GROUP defines a "section group", and + // its members have SHF_GROUP attribute. Usually these flags have already been + // stripped by InputFiles.cpp as section groups are processed and uniquified. + // However, for the -r option, we want to pass through all section groups + // as-is because adding/removing members or merging them with other groups + // change their semantics. + if (IS->Type == SHT_GROUP || (IS->Flags & SHF_GROUP)) + return createSection(IS, OutsecName); + + // Imagine .zed : { *(.foo) *(.bar) } script. Both foo and bar may have + // relocation sections .rela.foo and .rela.bar for example. Most tools do + // not allow multiple REL[A] sections for output section. Hence we + // should combine these relocation sections into single output. + // We skip synthetic sections because it can be .rela.dyn/.rela.plt or any + // other REL[A] sections created by linker itself. + if (!isa<SyntheticSection>(IS) && + (IS->Type == SHT_REL || IS->Type == SHT_RELA)) { + auto *Sec = cast<InputSection>(IS); + OutputSection *Out = Sec->getRelocatedSection()->getOutputSection(); + + if (Out->RelocationSection) { + Out->RelocationSection->addSection(Sec); + return nullptr; } + + Out->RelocationSection = createSection(IS, OutsecName); + return Out->RelocationSection; + } + + // When control reaches here, mergeable sections have already been merged into + // synthetic sections. For relocatable case we want to create one output + // section per syntetic section so that they have a valid sh_entsize. + if (Config->Relocatable && (IS->Flags & SHF_MERGE)) + return createSection(IS, OutsecName); + + // The ELF spec just says + // ---------------------------------------------------------------- + // In the first phase, input sections that match in name, type and + // attribute flags should be concatenated into single sections. + // ---------------------------------------------------------------- + // + // However, it is clear that at least some flags have to be ignored for + // section merging. At the very least SHF_GROUP and SHF_COMPRESSED have to be + // ignored. We should not have two output .text sections just because one was + // in a group and another was not for example. + // + // It also seems that that wording was a late addition and didn't get the + // necessary scrutiny. + // + // Merging sections with different flags is expected by some users. One + // reason is that if one file has + // + // int *const bar __attribute__((section(".foo"))) = (int *)0; + // + // gcc with -fPIC will produce a read only .foo section. But if another + // file has + // + // int zed; + // int *const bar __attribute__((section(".foo"))) = (int *)&zed; + // + // gcc with -fPIC will produce a read write section. + // + // Last but not least, when using linker script the merge rules are forced by + // the script. Unfortunately, linker scripts are name based. This means that + // expressions like *(.foo*) can refer to multiple input sections with + // different flags. We cannot put them in different output sections or we + // would produce wrong results for + // + // start = .; *(.foo.*) end = .; *(.bar) + // + // and a mapping of .foo1 and .bar1 to one section and .foo2 and .bar2 to + // another. The problem is that there is no way to layout those output + // sections such that the .foo sections are the only thing between the start + // and end symbols. + // + // Given the above issues, we instead merge sections by name and error on + // incompatible types and flags. + OutputSection *&Sec = Map[OutsecName]; + if (Sec) { + Sec->addSection(cast<InputSection>(IS)); + return nullptr; } - // SECTIONS commands run before other non SECTIONS commands - Commands.insert(Commands.end(), Opt.Commands.begin(), Opt.Commands.end()); - Opt.Commands = std::move(Commands); + + Sec = createSection(IS, OutsecName); + return Sec; } // Add sections that didn't match any sections command. -void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { - unsigned NumCommands = Opt.Commands.size(); +void LinkerScript::addOrphanSections() { + unsigned End = SectionCommands.size(); + StringMap<OutputSection *> Map; + + std::vector<OutputSection *> V; for (InputSectionBase *S : InputSections) { if (!S->Live || S->Parent) continue; - StringRef Name = getOutputSectionName(S->Name); - auto End = Opt.Commands.begin() + NumCommands; - auto I = std::find_if(Opt.Commands.begin(), End, [&](BaseCommand *Base) { - if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) - return Cmd->Name == Name; - return false; - }); - OutputSectionCommand *Cmd; - if (I == End) { - Factory.addInputSec(S, Name); - OutputSection *Sec = S->getOutputSection(); - assert(Sec->SectionIndex == INT_MAX); - OutputSectionCommand *&CmdRef = SecToCommand[Sec]; - if (!CmdRef) { - CmdRef = createOutputSectionCommand(Sec->Name, "<internal>"); - CmdRef->Sec = Sec; - Opt.Commands.push_back(CmdRef); - } - Cmd = CmdRef; - } else { - Cmd = cast<OutputSectionCommand>(*I); - Factory.addInputSec(S, Name, Cmd->Sec); - if (OutputSection *Sec = Cmd->Sec) { - SecToCommand[Sec] = Cmd; - unsigned Index = std::distance(Opt.Commands.begin(), I); - assert(Sec->SectionIndex == INT_MAX || Sec->SectionIndex == Index); - Sec->SectionIndex = Index; - } + + StringRef Name = getOutputSectionName(S); + + if (Config->OrphanHandling == OrphanHandlingPolicy::Error) + error(toString(S) + " is being placed in '" + Name + "'"); + else if (Config->OrphanHandling == OrphanHandlingPolicy::Warn) + warn(toString(S) + " is being placed in '" + Name + "'"); + + if (OutputSection *Sec = + findByName(makeArrayRef(SectionCommands).slice(0, End), Name)) { + Sec->addSection(cast<InputSection>(S)); + continue; } - auto *ISD = make<InputSectionDescription>(""); - ISD->Sections.push_back(cast<InputSection>(S)); - Cmd->Commands.push_back(ISD); + + if (OutputSection *OS = addInputSec(Map, S, Name)) + V.push_back(OS); + assert(S->getOutputSection()->SectionIndex == INT_MAX); } + + // If no SECTIONS command was given, we should insert sections commands + // before others, so that we can handle scripts which refers them, + // for example: "foo = ABSOLUTE(ADDR(.text)));". + // When SECTIONS command is present we just add all orphans to the end. + if (HasSectionsCommand) + SectionCommands.insert(SectionCommands.end(), V.begin(), V.end()); + else + SectionCommands.insert(SectionCommands.begin(), V.begin(), V.end()); } -uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) { - bool IsTbss = (CurAddressState->OutSec->Flags & SHF_TLS) && - CurAddressState->OutSec->Type == SHT_NOBITS; - uint64_t Start = IsTbss ? Dot + CurAddressState->ThreadBssOffset : Dot; - Start = alignTo(Start, Align); +uint64_t LinkerScript::advance(uint64_t Size, unsigned Alignment) { + bool IsTbss = + (Ctx->OutSec->Flags & SHF_TLS) && Ctx->OutSec->Type == SHT_NOBITS; + uint64_t Start = IsTbss ? Dot + Ctx->ThreadBssOffset : Dot; + Start = alignTo(Start, Alignment); uint64_t End = Start + Size; if (IsTbss) - CurAddressState->ThreadBssOffset = End - Dot; + Ctx->ThreadBssOffset = End - Dot; else Dot = End; return End; } void LinkerScript::output(InputSection *S) { + uint64_t Before = advance(0, 1); uint64_t Pos = advance(S->getSize(), S->Alignment); - S->OutSecOff = Pos - S->getSize() - CurAddressState->OutSec->Addr; + S->OutSecOff = Pos - S->getSize() - Ctx->OutSec->Addr; // Update output section size after adding each section. This is so that // SIZEOF works correctly in the case below: // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) } - CurAddressState->OutSec->Size = Pos - CurAddressState->OutSec->Addr; + Ctx->OutSec->Size = Pos - Ctx->OutSec->Addr; // If there is a memory region associated with this input section, then // place the section in that region and update the region index. - if (CurAddressState->MemRegion) { - uint64_t &CurOffset = - CurAddressState->MemRegionOffset[CurAddressState->MemRegion]; - CurOffset += CurAddressState->OutSec->Size; - uint64_t CurSize = CurOffset - CurAddressState->MemRegion->Origin; - if (CurSize > CurAddressState->MemRegion->Length) { - uint64_t OverflowAmt = CurSize - CurAddressState->MemRegion->Length; - error("section '" + CurAddressState->OutSec->Name + - "' will not fit in region '" + CurAddressState->MemRegion->Name + - "': overflowed by " + Twine(OverflowAmt) + " bytes"); + if (Ctx->MemRegion) { + uint64_t &CurOffset = Ctx->MemRegionOffset[Ctx->MemRegion]; + CurOffset += Pos - Before; + uint64_t CurSize = CurOffset - Ctx->MemRegion->Origin; + if (CurSize > Ctx->MemRegion->Length) { + uint64_t OverflowAmt = CurSize - Ctx->MemRegion->Length; + error("section '" + Ctx->OutSec->Name + "' will not fit in region '" + + Ctx->MemRegion->Name + "': overflowed by " + Twine(OverflowAmt) + + " bytes"); } } } void LinkerScript::switchTo(OutputSection *Sec) { - if (CurAddressState->OutSec == Sec) + if (Ctx->OutSec == Sec) return; - CurAddressState->OutSec = Sec; - CurAddressState->OutSec->Addr = - advance(0, CurAddressState->OutSec->Alignment); + Ctx->OutSec = Sec; + Ctx->OutSec->Addr = advance(0, Ctx->OutSec->Alignment); // If neither AT nor AT> is specified for an allocatable section, the linker // will set the LMA such that the difference between VMA and LMA for the // section is the same as the preceding output section in the same region // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html - if (CurAddressState->LMAOffset) - CurAddressState->OutSec->LMAOffset = CurAddressState->LMAOffset(); -} - -void LinkerScript::process(BaseCommand &Base) { - // This handles the assignments to symbol or to the dot. - if (auto *Cmd = dyn_cast<SymbolAssignment>(&Base)) { - assignSymbol(Cmd, true); - return; - } - - // Handle BYTE(), SHORT(), LONG(), or QUAD(). - if (auto *Cmd = dyn_cast<BytesDataCommand>(&Base)) { - Cmd->Offset = Dot - CurAddressState->OutSec->Addr; - Dot += Cmd->Size; - CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr; - return; - } - - // Handle ASSERT(). - if (auto *Cmd = dyn_cast<AssertCommand>(&Base)) { - Cmd->Expression(); - return; - } - - // Handle a single input section description command. - // It calculates and assigns the offsets for each section and also - // updates the output section size. - auto &Cmd = cast<InputSectionDescription>(Base); - for (InputSection *Sec : Cmd.Sections) { - // We tentatively added all synthetic sections at the beginning and removed - // empty ones afterwards (because there is no way to know whether they were - // going be empty or not other than actually running linker scripts.) - // We need to ignore remains of empty sections. - if (auto *S = dyn_cast<SyntheticSection>(Sec)) - if (S->empty()) - continue; - - if (!Sec->Live) - continue; - assert(CurAddressState->OutSec == Sec->getParent()); - output(Sec); - } + if (Ctx->LMAOffset) + Ctx->OutSec->LMAOffset = Ctx->LMAOffset(); } // This function searches for a memory region to place the given output // section in. If found, a pointer to the appropriate memory region is // returned. Otherwise, a nullptr is returned. -MemoryRegion *LinkerScript::findMemoryRegion(OutputSectionCommand *Cmd) { +MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) { // If a memory region name was specified in the output section command, // then try to find that region first. - if (!Cmd->MemoryRegionName.empty()) { - auto It = Opt.MemoryRegions.find(Cmd->MemoryRegionName); - if (It != Opt.MemoryRegions.end()) - return &It->second; - error("memory region '" + Cmd->MemoryRegionName + "' not declared"); + if (!Sec->MemoryRegionName.empty()) { + auto It = MemoryRegions.find(Sec->MemoryRegionName); + if (It != MemoryRegions.end()) + return It->second; + error("memory region '" + Sec->MemoryRegionName + "' not declared"); return nullptr; } // If at least one memory region is defined, all sections must // belong to some memory region. Otherwise, we don't need to do // anything for memory regions. - if (Opt.MemoryRegions.empty()) + if (MemoryRegions.empty()) return nullptr; - OutputSection *Sec = Cmd->Sec; // See if a region can be found by matching section flags. - for (auto &Pair : Opt.MemoryRegions) { - MemoryRegion &M = Pair.second; - if ((M.Flags & Sec->Flags) && (M.NegFlags & Sec->Flags) == 0) - return &M; + for (auto &Pair : MemoryRegions) { + MemoryRegion *M = Pair.second; + if ((M->Flags & Sec->Flags) && (M->NegFlags & Sec->Flags) == 0) + return M; } // Otherwise, no suitable region was found. @@ -667,33 +652,76 @@ MemoryRegion *LinkerScript::findMemoryRegion(OutputSectionCommand *Cmd) { // This function assigns offsets to input sections and an output section // for a single sections command (e.g. ".text { *(.text); }"). -void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { - OutputSection *Sec = Cmd->Sec; - if (!Sec) - return; - +void LinkerScript::assignOffsets(OutputSection *Sec) { if (!(Sec->Flags & SHF_ALLOC)) Dot = 0; - else if (Cmd->AddrExpr) - setDot(Cmd->AddrExpr, Cmd->Location, false); + else if (Sec->AddrExpr) + setDot(Sec->AddrExpr, Sec->Location, false); - if (Cmd->LMAExpr) { + Ctx->MemRegion = Sec->MemRegion; + if (Ctx->MemRegion) + Dot = Ctx->MemRegionOffset[Ctx->MemRegion]; + + if (Sec->LMAExpr) { uint64_t D = Dot; - CurAddressState->LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; }; + Ctx->LMAOffset = [=] { return Sec->LMAExpr().getValue() - D; }; } - CurAddressState->MemRegion = Cmd->MemRegion; - if (CurAddressState->MemRegion) - Dot = CurAddressState->MemRegionOffset[CurAddressState->MemRegion]; switchTo(Sec); // We do not support custom layout for compressed debug sectons. // At this point we already know their size and have compressed content. - if (CurAddressState->OutSec->Flags & SHF_COMPRESSED) + if (Ctx->OutSec->Flags & SHF_COMPRESSED) return; - for (BaseCommand *C : Cmd->Commands) - process(*C); + // The Size previously denoted how many InputSections had been added to this + // section, and was used for sorting SHF_LINK_ORDER sections. Reset it to + // compute the actual size value. + Sec->Size = 0; + + // We visited SectionsCommands from processSectionCommands to + // layout sections. Now, we visit SectionsCommands again to fix + // section offsets. + for (BaseCommand *Base : Sec->SectionCommands) { + // This handles the assignments to symbol or to the dot. + if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { + assignSymbol(Cmd, true); + continue; + } + + // Handle BYTE(), SHORT(), LONG(), or QUAD(). + if (auto *Cmd = dyn_cast<ByteCommand>(Base)) { + Cmd->Offset = Dot - Ctx->OutSec->Addr; + Dot += Cmd->Size; + Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr; + continue; + } + + // Handle ASSERT(). + if (auto *Cmd = dyn_cast<AssertCommand>(Base)) { + Cmd->Expression(); + continue; + } + + // Handle a single input section description command. + // It calculates and assigns the offsets for each section and also + // updates the output section size. + auto *Cmd = cast<InputSectionDescription>(Base); + for (InputSection *Sec : Cmd->Sections) { + // We tentatively added all synthetic sections at the beginning and + // removed empty ones afterwards (because there is no way to know + // whether they were going be empty or not other than actually running + // linker scripts.) We need to ignore remains of empty sections. + if (auto *S = dyn_cast<SyntheticSection>(Sec)) + if (S->empty()) + continue; + + if (!Sec->Live) + continue; + assert(Ctx->OutSec == Sec->getParent()); + output(Sec); + } + } } void LinkerScript::removeEmptyCommands() { @@ -703,17 +731,15 @@ void LinkerScript::removeEmptyCommands() { // clutter the output. // We instead remove trivially empty sections. The bfd linker seems even // more aggressive at removing them. - auto Pos = std::remove_if( - Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) { - if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) - return Cmd->Sec == nullptr; - return false; - }); - Opt.Commands.erase(Pos, Opt.Commands.end()); + llvm::erase_if(SectionCommands, [&](BaseCommand *Base) { + if (auto *Sec = dyn_cast<OutputSection>(Base)) + return !Sec->Live; + return false; + }); } -static bool isAllSectionDescription(const OutputSectionCommand &Cmd) { - for (BaseCommand *Base : Cmd.Commands) +static bool isAllSectionDescription(const OutputSection &Cmd) { + for (BaseCommand *Base : Cmd.SectionCommands) if (!isa<InputSectionDescription>(*Base)) return false; return true; @@ -721,38 +747,55 @@ static bool isAllSectionDescription(const OutputSectionCommand &Cmd) { void LinkerScript::adjustSectionsBeforeSorting() { // If the output section contains only symbol assignments, create a - // corresponding output section. The bfd linker seems to only create them if - // '.' is assigned to, but creating these section should not have any bad - // consequeces and gives us a section to put the symbol in. + // corresponding output section. The issue is what to do with linker script + // like ".foo : { symbol = 42; }". One option would be to convert it to + // "symbol = 42;". That is, move the symbol out of the empty section + // description. That seems to be what bfd does for this simple case. The + // problem is that this is not completely general. bfd will give up and + // create a dummy section too if there is a ". = . + 1" inside the section + // for example. + // Given that we want to create the section, we have to worry what impact + // it will have on the link. For example, if we just create a section with + // 0 for flags, it would change which PT_LOADs are created. + // We could remember that that particular section is dummy and ignore it in + // other parts of the linker, but unfortunately there are quite a few places + // that would need to change: + // * The program header creation. + // * The orphan section placement. + // * The address assignment. + // The other option is to pick flags that minimize the impact the section + // will have on the rest of the linker. That is why we copy the flags from + // the previous sections. Only a few flags are needed to keep the impact low. uint64_t Flags = SHF_ALLOC; - for (int I = 0, E = Opt.Commands.size(); I != E; ++I) { - auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I]); - if (!Cmd) + for (BaseCommand *Cmd : SectionCommands) { + auto *Sec = dyn_cast<OutputSection>(Cmd); + if (!Sec) continue; - if (OutputSection *Sec = Cmd->Sec) { - Flags = Sec->Flags; + if (Sec->Live) { + Flags = Sec->Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR); continue; } - if (isAllSectionDescription(*Cmd)) + if (isAllSectionDescription(*Sec)) continue; - auto *OutSec = make<OutputSection>(Cmd->Name, SHT_PROGBITS, Flags); - OutSec->SectionIndex = I; - Cmd->Sec = OutSec; - SecToCommand[OutSec] = Cmd; + Sec->Live = true; + Sec->Flags = Flags; } } void LinkerScript::adjustSectionsAfterSorting() { // Try and find an appropriate memory region to assign offsets in. - for (BaseCommand *Base : Opt.Commands) { - if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) { - Cmd->MemRegion = findMemoryRegion(Cmd); + for (BaseCommand *Base : SectionCommands) { + if (auto *Sec = dyn_cast<OutputSection>(Base)) { + if (!Sec->Live) + continue; + Sec->MemRegion = findMemoryRegion(Sec); // Handle align (e.g. ".foo : ALIGN(16) { ... }"). - if (Cmd->AlignExpr) - Cmd->Sec->updateAlignment(Cmd->AlignExpr().getValue()); + if (Sec->AlignExpr) + Sec->Alignment = + std::max<uint32_t>(Sec->Alignment, Sec->AlignExpr().getValue()); } } @@ -764,108 +807,112 @@ void LinkerScript::adjustSectionsAfterSorting() { // SECTIONS { .aaa : { *(.aaa) } } std::vector<StringRef> DefPhdrs; auto FirstPtLoad = - std::find_if(Opt.PhdrsCommands.begin(), Opt.PhdrsCommands.end(), + std::find_if(PhdrsCommands.begin(), PhdrsCommands.end(), [](const PhdrsCommand &Cmd) { return Cmd.Type == PT_LOAD; }); - if (FirstPtLoad != Opt.PhdrsCommands.end()) + if (FirstPtLoad != PhdrsCommands.end()) DefPhdrs.push_back(FirstPtLoad->Name); // Walk the commands and propagate the program headers to commands that don't // explicitly specify them. - for (BaseCommand *Base : Opt.Commands) { - auto *Cmd = dyn_cast<OutputSectionCommand>(Base); - if (!Cmd) + for (BaseCommand *Base : SectionCommands) { + auto *Sec = dyn_cast<OutputSection>(Base); + if (!Sec) continue; - if (Cmd->Phdrs.empty()) { - OutputSection *Sec = Cmd->Sec; + if (Sec->Phdrs.empty()) { // To match the bfd linker script behaviour, only propagate program // headers to sections that are allocated. - if (Sec && (Sec->Flags & SHF_ALLOC)) - Cmd->Phdrs = DefPhdrs; + if (Sec->Flags & SHF_ALLOC) + Sec->Phdrs = DefPhdrs; } else { - DefPhdrs = Cmd->Phdrs; + DefPhdrs = Sec->Phdrs; } } - - removeEmptyCommands(); } -void LinkerScript::processNonSectionCommands() { - for (BaseCommand *Base : Opt.Commands) { - if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) - assignSymbol(Cmd, false); - else if (auto *Cmd = dyn_cast<AssertCommand>(Base)) - Cmd->Expression(); - } +static OutputSection *findFirstSection(PhdrEntry *Load) { + for (OutputSection *Sec : OutputSections) + if (Sec->PtLoad == Load) + return Sec; + return nullptr; } -void LinkerScript::allocateHeaders(std::vector<PhdrEntry> &Phdrs) { +// Try to find an address for the file and program headers output sections, +// which were unconditionally added to the first PT_LOAD segment earlier. +// +// When using the default layout, we check if the headers fit below the first +// allocated section. When using a linker script, we also check if the headers +// are covered by the output section. This allows omitting the headers by not +// leaving enough space for them in the linker script; this pattern is common +// in embedded systems. +// +// If there isn't enough space for these sections, we'll remove them from the +// PT_LOAD segment, and we'll also remove the PT_PHDR segment. +void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &Phdrs) { uint64_t Min = std::numeric_limits<uint64_t>::max(); - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; + for (OutputSection *Sec : OutputSections) if (Sec->Flags & SHF_ALLOC) Min = std::min<uint64_t>(Min, Sec->Addr); - } - auto FirstPTLoad = llvm::find_if( - Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); - if (FirstPTLoad == Phdrs.end()) + auto It = llvm::find_if( + Phdrs, [](const PhdrEntry *E) { return E->p_type == PT_LOAD; }); + if (It == Phdrs.end()) return; + PhdrEntry *FirstPTLoad = *It; uint64_t HeaderSize = getHeaderSize(); - if (HeaderSize <= Min || Script->hasPhdrsCommands()) { + // When linker script with SECTIONS is being used, don't output headers + // unless there's a space for them. + uint64_t Base = HasSectionsCommand ? alignDown(Min, Config->MaxPageSize) : 0; + if (HeaderSize <= Min - Base || Script->hasPhdrsCommands()) { Min = alignDown(Min - HeaderSize, Config->MaxPageSize); Out::ElfHeader->Addr = Min; Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; return; } - assert(FirstPTLoad->First == Out::ElfHeader); - OutputSection *ActualFirst = nullptr; - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; - if (Sec->FirstInPtLoad == Out::ElfHeader) { - ActualFirst = Sec; - break; - } - } - if (ActualFirst) { - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; - if (Sec->FirstInPtLoad == Out::ElfHeader) - Sec->FirstInPtLoad = ActualFirst; - } - FirstPTLoad->First = ActualFirst; - } else { - Phdrs.erase(FirstPTLoad); - } + Out::ElfHeader->PtLoad = nullptr; + Out::ProgramHeaders->PtLoad = nullptr; + FirstPTLoad->FirstSec = findFirstSection(FirstPTLoad); - auto PhdrI = llvm::find_if( - Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_PHDR; }); - if (PhdrI != Phdrs.end()) - Phdrs.erase(PhdrI); + llvm::erase_if(Phdrs, + [](const PhdrEntry *E) { return E->p_type == PT_PHDR; }); } -LinkerScript::AddressState::AddressState(const ScriptConfiguration &Opt) { - for (auto &MRI : Opt.MemoryRegions) { - const MemoryRegion *MR = &MRI.second; +LinkerScript::AddressState::AddressState() { + for (auto &MRI : Script->MemoryRegions) { + const MemoryRegion *MR = MRI.second; MemRegionOffset[MR] = MR->Origin; } } +static uint64_t getInitialDot() { + // By default linker scripts use an initial value of 0 for '.', + // but prefer -image-base if set. + if (Script->HasSectionsCommand) + return Config->ImageBase ? *Config->ImageBase : 0; + + uint64_t StartAddr = UINT64_MAX; + // The Sections with -T<section> have been sorted in order of ascending + // address. We must lower StartAddr if the lowest -T<section address> as + // calls to setDot() must be monotonically increasing. + for (auto &KV : Config->SectionStartMap) + StartAddr = std::min(StartAddr, KV.second); + return std::min(StartAddr, Target->getImageBase() + elf::getHeaderSize()); +} + +// Here we assign addresses as instructed by linker script SECTIONS +// sub-commands. Doing that allows us to use final VA values, so here +// we also handle rest commands like symbol assignments and ASSERTs. void LinkerScript::assignAddresses() { - // Assign addresses as instructed by linker script SECTIONS sub-commands. - Dot = 0; - auto State = make_unique<AddressState>(Opt); - // CurAddressState captures the local AddressState and makes it accessible - // deliberately. This is needed as there are some cases where we cannot just - // thread the current state through to a lambda function created by the - // script parser. - CurAddressState = State.get(); + Dot = getInitialDot(); + + auto Deleter = make_unique<AddressState>(); + Ctx = Deleter.get(); ErrorOnMissingSection = true; switchTo(Aether); - for (BaseCommand *Base : Opt.Commands) { + for (BaseCommand *Base : SectionCommands) { if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { assignSymbol(Cmd, false); continue; @@ -876,380 +923,98 @@ void LinkerScript::assignAddresses() { continue; } - auto *Cmd = cast<OutputSectionCommand>(Base); - assignOffsets(Cmd); + assignOffsets(cast<OutputSection>(Base)); } - CurAddressState = nullptr; + Ctx = nullptr; } // Creates program headers as instructed by PHDRS linker script command. -std::vector<PhdrEntry> LinkerScript::createPhdrs() { - std::vector<PhdrEntry> Ret; +std::vector<PhdrEntry *> LinkerScript::createPhdrs() { + std::vector<PhdrEntry *> Ret; // Process PHDRS and FILEHDR keywords because they are not // real output sections and cannot be added in the following loop. - for (const PhdrsCommand &Cmd : Opt.PhdrsCommands) { - Ret.emplace_back(Cmd.Type, Cmd.Flags == UINT_MAX ? PF_R : Cmd.Flags); - PhdrEntry &Phdr = Ret.back(); + for (const PhdrsCommand &Cmd : PhdrsCommands) { + PhdrEntry *Phdr = make<PhdrEntry>(Cmd.Type, Cmd.Flags ? *Cmd.Flags : PF_R); if (Cmd.HasFilehdr) - Phdr.add(Out::ElfHeader); + Phdr->add(Out::ElfHeader); if (Cmd.HasPhdrs) - Phdr.add(Out::ProgramHeaders); + Phdr->add(Out::ProgramHeaders); if (Cmd.LMAExpr) { - Phdr.p_paddr = Cmd.LMAExpr().getValue(); - Phdr.HasLMA = true; + Phdr->p_paddr = Cmd.LMAExpr().getValue(); + Phdr->HasLMA = true; } + Ret.push_back(Phdr); } // Add output sections to program headers. - for (OutputSectionCommand *Cmd : OutputSectionCommands) { + for (OutputSection *Sec : OutputSections) { // Assign headers specified by linker script - for (size_t Id : getPhdrIndices(Cmd)) { - OutputSection *Sec = Cmd->Sec; - Ret[Id].add(Sec); - if (Opt.PhdrsCommands[Id].Flags == UINT_MAX) - Ret[Id].p_flags |= Sec->getPhdrFlags(); + for (size_t Id : getPhdrIndices(Sec)) { + Ret[Id]->add(Sec); + if (!PhdrsCommands[Id].Flags.hasValue()) + Ret[Id]->p_flags |= Sec->getPhdrFlags(); } } return Ret; } -bool LinkerScript::ignoreInterpSection() { - // Ignore .interp section in case we have PHDRS specification - // and PT_INTERP isn't listed. - if (Opt.PhdrsCommands.empty()) - return false; - for (PhdrsCommand &Cmd : Opt.PhdrsCommands) - if (Cmd.Type == PT_INTERP) - return false; - return true; -} - -OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const { - auto I = SecToCommand.find(Sec); - if (I == SecToCommand.end()) - return nullptr; - return I->second; -} - -void OutputSectionCommand::sort(std::function<int(InputSectionBase *S)> Order) { - typedef std::pair<unsigned, InputSection *> Pair; - auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; - - std::vector<Pair> V; - assert(Commands.size() == 1); - auto *ISD = cast<InputSectionDescription>(Commands[0]); - for (InputSection *S : ISD->Sections) - V.push_back({Order(S), S}); - std::stable_sort(V.begin(), V.end(), Comp); - ISD->Sections.clear(); - for (Pair &P : V) - ISD->Sections.push_back(P.second); -} - -// Returns true if S matches /Filename.?\.o$/. -static bool isCrtBeginEnd(StringRef S, StringRef Filename) { - if (!S.endswith(".o")) - return false; - S = S.drop_back(2); - if (S.endswith(Filename)) - return true; - return !S.empty() && S.drop_back().endswith(Filename); -} - -static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); } -static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); } - -// .ctors and .dtors are sorted by this priority from highest to lowest. -// -// 1. The section was contained in crtbegin (crtbegin contains -// some sentinel value in its .ctors and .dtors so that the runtime -// can find the beginning of the sections.) -// -// 2. The section has an optional priority value in the form of ".ctors.N" -// or ".dtors.N" where N is a number. Unlike .{init,fini}_array, -// they are compared as string rather than number. -// -// 3. The section is just ".ctors" or ".dtors". +// Returns true if we should emit an .interp section. // -// 4. The section was contained in crtend, which contains an end marker. -// -// In an ideal world, we don't need this function because .init_array and -// .ctors are duplicate features (and .init_array is newer.) However, there -// are too many real-world use cases of .ctors, so we had no choice to -// support that with this rather ad-hoc semantics. -static bool compCtors(const InputSection *A, const InputSection *B) { - bool BeginA = isCrtbegin(A->File->getName()); - bool BeginB = isCrtbegin(B->File->getName()); - if (BeginA != BeginB) - return BeginA; - bool EndA = isCrtend(A->File->getName()); - bool EndB = isCrtend(B->File->getName()); - if (EndA != EndB) - return EndB; - StringRef X = A->Name; - StringRef Y = B->Name; - assert(X.startswith(".ctors") || X.startswith(".dtors")); - assert(Y.startswith(".ctors") || Y.startswith(".dtors")); - X = X.substr(6); - Y = Y.substr(6); - if (X.empty() && Y.empty()) - return false; - return X < Y; -} - -// Sorts input sections by the special rules for .ctors and .dtors. -// Unfortunately, the rules are different from the one for .{init,fini}_array. -// Read the comment above. -void OutputSectionCommand::sortCtorsDtors() { - assert(Commands.size() == 1); - auto *ISD = cast<InputSectionDescription>(Commands[0]); - std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors); -} - -// Sorts input sections by section name suffixes, so that .foo.N comes -// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections. -// We want to keep the original order if the priorities are the same -// because the compiler keeps the original initialization order in a -// translation unit and we need to respect that. -// For more detail, read the section of the GCC's manual about init_priority. -void OutputSectionCommand::sortInitFini() { - // Sort sections by priority. - sort([](InputSectionBase *S) { return getPriority(S->Name); }); -} - -uint32_t OutputSectionCommand::getFiller() { - if (Filler) - return *Filler; - if (Sec->Flags & SHF_EXECINSTR) - return Target->TrapInstr; - return 0; -} - -static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { - if (Size == 1) - *Buf = Data; - else if (Size == 2) - write16(Buf, Data, Config->Endianness); - else if (Size == 4) - write32(Buf, Data, Config->Endianness); - else if (Size == 8) - write64(Buf, Data, Config->Endianness); - else - llvm_unreachable("unsupported Size argument"); -} - -static bool compareByFilePosition(InputSection *A, InputSection *B) { - // Synthetic doesn't have link order dependecy, stable_sort will keep it last - if (A->kind() == InputSectionBase::Synthetic || - B->kind() == InputSectionBase::Synthetic) - return false; - InputSection *LA = A->getLinkOrderDep(); - InputSection *LB = B->getLinkOrderDep(); - OutputSection *AOut = LA->getParent(); - OutputSection *BOut = LB->getParent(); - if (AOut != BOut) - return AOut->SectionIndex < BOut->SectionIndex; - return LA->OutSecOff < LB->OutSecOff; -} - -template <class ELFT> -static void finalizeShtGroup(OutputSection *OS, - ArrayRef<InputSection *> Sections) { - assert(Config->Relocatable && Sections.size() == 1); - - // sh_link field for SHT_GROUP sections should contain the section index of - // the symbol table. - OS->Link = InX::SymTab->getParent()->SectionIndex; - - // sh_info then contain index of an entry in symbol table section which - // provides signature of the section group. - elf::ObjectFile<ELFT> *Obj = Sections[0]->getFile<ELFT>(); - ArrayRef<SymbolBody *> Symbols = Obj->getSymbols(); - OS->Info = InX::SymTab->getSymbolIndex(Symbols[Sections[0]->Info - 1]); +// We usually do. But if PHDRS commands are given, and +// no PT_INTERP is there, there's no place to emit an +// .interp, so we don't do that in that case. +bool LinkerScript::needsInterpSection() { + if (PhdrsCommands.empty()) + return true; + for (PhdrsCommand &Cmd : PhdrsCommands) + if (Cmd.Type == PT_INTERP) + return true; + return false; } -template <class ELFT> void OutputSectionCommand::finalize() { - // Link order may be distributed across several InputSectionDescriptions - // but sort must consider them all at once. - std::vector<InputSection **> ScriptSections; - std::vector<InputSection *> Sections; - for (BaseCommand *Base : Commands) - if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) - for (InputSection *&IS : ISD->Sections) { - ScriptSections.push_back(&IS); - Sections.push_back(IS); - } - - if ((Sec->Flags & SHF_LINK_ORDER)) { - std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition); - for (int I = 0, N = Sections.size(); I < N; ++I) - *ScriptSections[I] = Sections[I]; - - // We must preserve the link order dependency of sections with the - // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We - // need to translate the InputSection sh_link to the OutputSection sh_link, - // all InputSections in the OutputSection have the same dependency. - if (auto *D = Sections.front()->getLinkOrderDep()) - Sec->Link = D->getParent()->SectionIndex; +ExprValue LinkerScript::getSymbolValue(StringRef Name, const Twine &Loc) { + if (Name == ".") { + if (Ctx) + return {Ctx->OutSec, false, Dot - Ctx->OutSec->Addr, Loc}; + error(Loc + ": unable to get location counter value"); + return 0; } - uint32_t Type = Sec->Type; - if (Type == SHT_GROUP) { - finalizeShtGroup<ELFT>(Sec, Sections); - return; - } - - if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) - return; - - InputSection *First = Sections[0]; - if (isa<SyntheticSection>(First)) - return; - - Sec->Link = InX::SymTab->getParent()->SectionIndex; - // sh_info for SHT_REL[A] sections should contain the section header index of - // the section to which the relocation applies. - InputSectionBase *S = First->getRelocatedSection(); - Sec->Info = S->getOutputSection()->SectionIndex; - Sec->Flags |= SHF_INFO_LINK; -} - -// Compress section contents if this section contains debug info. -template <class ELFT> void OutputSectionCommand::maybeCompress() { - typedef typename ELFT::Chdr Elf_Chdr; - - // Compress only DWARF debug sections. - if (!Config->CompressDebugSections || (Sec->Flags & SHF_ALLOC) || - !Name.startswith(".debug_")) - return; - - // Create a section header. - Sec->ZDebugHeader.resize(sizeof(Elf_Chdr)); - auto *Hdr = reinterpret_cast<Elf_Chdr *>(Sec->ZDebugHeader.data()); - Hdr->ch_type = ELFCOMPRESS_ZLIB; - Hdr->ch_size = Sec->Size; - Hdr->ch_addralign = Sec->Alignment; - - // Write section contents to a temporary buffer and compress it. - std::vector<uint8_t> Buf(Sec->Size); - writeTo<ELFT>(Buf.data()); - if (Error E = zlib::compress(toStringRef(Buf), Sec->CompressedData)) - fatal("compress failed: " + llvm::toString(std::move(E))); - - // Update section headers. - Sec->Size = sizeof(Elf_Chdr) + Sec->CompressedData.size(); - Sec->Flags |= SHF_COMPRESSED; -} - -template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) { - if (Sec->Type == SHT_NOBITS) - return; - - Sec->Loc = Buf; - - // If -compress-debug-section is specified and if this is a debug seciton, - // we've already compressed section contents. If that's the case, - // just write it down. - if (!Sec->CompressedData.empty()) { - memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size()); - memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(), - Sec->CompressedData.size()); - return; + if (Symbol *Sym = Symtab->find(Name)) { + if (auto *DS = dyn_cast<Defined>(Sym)) + return {DS->Section, false, DS->Value, Loc}; + if (auto *SS = dyn_cast<SharedSymbol>(Sym)) + if (!ErrorOnMissingSection || SS->CopyRelSec) + return {SS->CopyRelSec, false, 0, Loc}; } - // Write leading padding. - std::vector<InputSection *> Sections; - for (BaseCommand *Cmd : Commands) - if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd)) - for (InputSection *IS : ISD->Sections) - if (IS->Live) - Sections.push_back(IS); - uint32_t Filler = getFiller(); - if (Filler) - fill(Buf, Sections.empty() ? Sec->Size : Sections[0]->OutSecOff, Filler); - - parallelForEachN(0, Sections.size(), [=](size_t I) { - InputSection *IS = Sections[I]; - IS->writeTo<ELFT>(Buf); - - // Fill gaps between sections. - if (Filler) { - uint8_t *Start = Buf + IS->OutSecOff + IS->getSize(); - uint8_t *End; - if (I + 1 == Sections.size()) - End = Buf + Sec->Size; - else - End = Buf + Sections[I + 1]->OutSecOff; - fill(Start, End - Start, Filler); - } - }); - - // Linker scripts may have BYTE()-family commands with which you - // can write arbitrary bytes to the output. Process them if any. - for (BaseCommand *Base : Commands) - if (auto *Data = dyn_cast<BytesDataCommand>(Base)) - writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); -} - -ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { - if (S == ".") - return {CurAddressState->OutSec, Dot - CurAddressState->OutSec->Addr, Loc}; - if (SymbolBody *B = findSymbol(S)) { - if (auto *D = dyn_cast<DefinedRegular>(B)) - return {D->Section, D->Value, Loc}; - if (auto *C = dyn_cast<DefinedCommon>(B)) - return {InX::Common, C->Offset, Loc}; - } - error(Loc + ": symbol not found: " + S); + error(Loc + ": symbol not found: " + Name); return 0; } -bool LinkerScript::isDefined(StringRef S) { return findSymbol(S) != nullptr; } - -static const size_t NoPhdr = -1; +// Returns the index of the segment named Name. +static Optional<size_t> getPhdrIndex(ArrayRef<PhdrsCommand> Vec, + StringRef Name) { + for (size_t I = 0; I < Vec.size(); ++I) + if (Vec[I].Name == Name) + return I; + return None; +} // Returns indices of ELF headers containing specific section. Each index is a // zero based number of ELF header listed within PHDRS {} script block. -std::vector<size_t> LinkerScript::getPhdrIndices(OutputSectionCommand *Cmd) { +std::vector<size_t> LinkerScript::getPhdrIndices(OutputSection *Cmd) { std::vector<size_t> Ret; - for (StringRef PhdrName : Cmd->Phdrs) { - size_t Index = getPhdrIndex(Cmd->Location, PhdrName); - if (Index != NoPhdr) - Ret.push_back(Index); - } - return Ret; -} -// Returns the index of the segment named PhdrName if found otherwise -// NoPhdr. When not found, if PhdrName is not the special case value 'NONE' -// (which can be used to explicitly specify that a section isn't assigned to a -// segment) then error. -size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) { - size_t I = 0; - for (PhdrsCommand &Cmd : Opt.PhdrsCommands) { - if (Cmd.Name == PhdrName) - return I; - ++I; + for (StringRef S : Cmd->Phdrs) { + if (Optional<size_t> Idx = getPhdrIndex(PhdrsCommands, S)) + Ret.push_back(*Idx); + else if (S != "NONE") + error(Cmd->Location + ": section header '" + S + + "' is not listed in PHDRS"); } - if (PhdrName != "NONE") - error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS"); - return NoPhdr; + return Ret; } - -template void OutputSectionCommand::writeTo<ELF32LE>(uint8_t *Buf); -template void OutputSectionCommand::writeTo<ELF32BE>(uint8_t *Buf); -template void OutputSectionCommand::writeTo<ELF64LE>(uint8_t *Buf); -template void OutputSectionCommand::writeTo<ELF64BE>(uint8_t *Buf); - -template void OutputSectionCommand::maybeCompress<ELF32LE>(); -template void OutputSectionCommand::maybeCompress<ELF32BE>(); -template void OutputSectionCommand::maybeCompress<ELF64LE>(); -template void OutputSectionCommand::maybeCompress<ELF64BE>(); - -template void OutputSectionCommand::finalize<ELF32LE>(); -template void OutputSectionCommand::finalize<ELF32BE>(); -template void OutputSectionCommand::finalize<ELF64LE>(); -template void OutputSectionCommand::finalize<ELF64BE>(); diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h index dd5a7d797f60..11131dda8e26 100644 --- a/ELF/LinkerScript.h +++ b/ELF/LinkerScript.h @@ -13,10 +13,11 @@ #include "Config.h" #include "Strings.h" #include "Writer.h" -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/MemoryBuffer.h" #include <cstddef> @@ -28,31 +29,39 @@ namespace lld { namespace elf { -class DefinedCommon; -class SymbolBody; +class Defined; +class Symbol; class InputSectionBase; class InputSection; class OutputSection; -class OutputSectionFactory; class InputSectionBase; class SectionBase; +// This represents an r-value in the linker script. struct ExprValue { - SectionBase *Sec; - uint64_t Val; - bool ForceAbsolute; - uint64_t Alignment = 1; - std::string Loc; - ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val, const Twine &Loc) - : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute), Loc(Loc.str()) {} - ExprValue(SectionBase *Sec, uint64_t Val, const Twine &Loc) - : ExprValue(Sec, false, Val, Loc) {} - ExprValue(uint64_t Val) : ExprValue(nullptr, Val, "") {} + : Sec(Sec), ForceAbsolute(ForceAbsolute), Val(Val), Loc(Loc.str()) {} + + ExprValue(uint64_t Val) : ExprValue(nullptr, false, Val, "") {} + bool isAbsolute() const { return ForceAbsolute || Sec == nullptr; } uint64_t getValue() const; uint64_t getSecAddr() const; + uint64_t getSectionOffset() const; + + // If a value is relative to a section, it has a non-null Sec. + SectionBase *Sec; + + // True if this expression is enclosed in ABSOLUTE(). + // This flag affects the return value of getValue(). + bool ForceAbsolute; + + uint64_t Val; + uint64_t Alignment = 1; + + // Original source location. Used for error messages. + std::string Loc; }; // This represents an expression in the linker script. @@ -66,8 +75,8 @@ enum SectionsCommandKind { AssignmentKind, // . = expr or <sym> = expr OutputSectionKind, InputSectionKind, - AssertKind, // ASSERT(expr) - BytesDataKind // BYTE(expr), SHORT(expr), LONG(expr) or QUAD(expr) + AssertKind, // ASSERT(expr) + ByteKind // BYTE(expr), SHORT(expr), LONG(expr) or QUAD(expr) }; struct BaseCommand { @@ -80,11 +89,13 @@ struct SymbolAssignment : BaseCommand { SymbolAssignment(StringRef Name, Expr E, std::string Loc) : BaseCommand(AssignmentKind), Name(Name), Expression(E), Location(Loc) {} - static bool classof(const BaseCommand *C); + static bool classof(const BaseCommand *C) { + return C->Kind == AssignmentKind; + } // The LHS of an expression. Name is either a symbol name or ".". StringRef Name; - SymbolBody *Sym = nullptr; + Defined *Sym = nullptr; // The RHS of an expression. Expr Expression; @@ -114,37 +125,6 @@ struct MemoryRegion { uint32_t NegFlags; }; -struct OutputSectionCommand : BaseCommand { - OutputSectionCommand(StringRef Name) - : BaseCommand(OutputSectionKind), Name(Name) {} - - static bool classof(const BaseCommand *C); - - OutputSection *Sec = nullptr; - MemoryRegion *MemRegion = nullptr; - StringRef Name; - Expr AddrExpr; - Expr AlignExpr; - Expr LMAExpr; - Expr SubalignExpr; - std::vector<BaseCommand *> Commands; - std::vector<StringRef> Phdrs; - llvm::Optional<uint32_t> Filler; - ConstraintKind Constraint = ConstraintKind::NoConstraint; - std::string Location; - std::string MemoryRegionName; - bool Noload = false; - - template <class ELFT> void finalize(); - template <class ELFT> void writeTo(uint8_t *Buf); - template <class ELFT> void maybeCompress(); - uint32_t getFiller(); - - void sort(std::function<int(InputSectionBase *S)> Order); - void sortInitFini(); - void sortCtorsDtors(); -}; - // This struct represents one section match pattern in SECTIONS() command. // It can optionally have negative match pattern for EXCLUDED_FILE command. // Also it may be surrounded with SORT() command, so contains sorting rules. @@ -158,11 +138,14 @@ struct SectionPattern { SortSectionPolicy SortInner; }; +class ThunkSection; struct InputSectionDescription : BaseCommand { InputSectionDescription(StringRef FilePattern) : BaseCommand(InputSectionKind), FilePat(FilePattern) {} - static bool classof(const BaseCommand *C); + static bool classof(const BaseCommand *C) { + return C->Kind == InputSectionKind; + } StringMatcher FilePat; @@ -171,23 +154,28 @@ struct InputSectionDescription : BaseCommand { std::vector<SectionPattern> SectionPatterns; std::vector<InputSection *> Sections; + + // Temporary record of synthetic ThunkSection instances and the pass that + // they were created in. This is used to insert newly created ThunkSections + // into Sections at the end of a createThunks() pass. + std::vector<std::pair<ThunkSection *, uint32_t>> ThunkSections; }; // Represents an ASSERT(). struct AssertCommand : BaseCommand { AssertCommand(Expr E) : BaseCommand(AssertKind), Expression(E) {} - static bool classof(const BaseCommand *C); + static bool classof(const BaseCommand *C) { return C->Kind == AssertKind; } Expr Expression; }; // Represents BYTE(), SHORT(), LONG(), or QUAD(). -struct BytesDataCommand : BaseCommand { - BytesDataCommand(Expr E, unsigned Size) - : BaseCommand(BytesDataKind), Expression(E), Size(Size) {} +struct ByteCommand : BaseCommand { + ByteCommand(Expr E, unsigned Size) + : BaseCommand(ByteKind), Expression(E), Size(Size) {} - static bool classof(const BaseCommand *C); + static bool classof(const BaseCommand *C) { return C->Kind == ByteKind; } Expr Expression; unsigned Offset; @@ -196,106 +184,103 @@ struct BytesDataCommand : BaseCommand { struct PhdrsCommand { StringRef Name; - unsigned Type; - bool HasFilehdr; - bool HasPhdrs; - unsigned Flags; - Expr LMAExpr; -}; - -// ScriptConfiguration holds linker script parse results. -struct ScriptConfiguration { - // Used to assign addresses to sections. - std::vector<BaseCommand *> Commands; - - // Used to assign sections to headers. - std::vector<PhdrsCommand> PhdrsCommands; - - bool HasSections = false; - - // List of section patterns specified with KEEP commands. They will - // be kept even if they are unused and --gc-sections is specified. - std::vector<InputSectionDescription *> KeptSections; - - // A map from memory region name to a memory region descriptor. - llvm::DenseMap<llvm::StringRef, MemoryRegion> MemoryRegions; - - // A list of symbols referenced by the script. - std::vector<llvm::StringRef> ReferencedSymbols; + unsigned Type = llvm::ELF::PT_NULL; + bool HasFilehdr = false; + bool HasPhdrs = false; + llvm::Optional<unsigned> Flags; + Expr LMAExpr = nullptr; }; class LinkerScript final { - // Temporary state used in processCommands() and assignAddresses() + // Temporary state used in processSectionCommands() and assignAddresses() // that must be reinitialized for each call to the above functions, and must // not be used outside of the scope of a call to the above functions. struct AddressState { + AddressState(); uint64_t ThreadBssOffset = 0; OutputSection *OutSec = nullptr; MemoryRegion *MemRegion = nullptr; llvm::DenseMap<const MemoryRegion *, uint64_t> MemRegionOffset; std::function<uint64_t()> LMAOffset; - AddressState(const ScriptConfiguration &Opt); }; - llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand; - llvm::DenseMap<StringRef, OutputSectionCommand *> NameToOutputSectionCommand; + llvm::DenseMap<StringRef, OutputSection *> NameToOutputSection; + + void addSymbol(SymbolAssignment *Cmd); void assignSymbol(SymbolAssignment *Cmd, bool InSec); void setDot(Expr E, const Twine &Loc, bool InSec); std::vector<InputSection *> - computeInputSections(const InputSectionDescription *); + computeInputSections(const InputSectionDescription *, + const llvm::DenseMap<SectionBase *, int> &Order); - std::vector<InputSectionBase *> - createInputSectionList(OutputSectionCommand &Cmd); + std::vector<InputSection *> + createInputSectionList(OutputSection &Cmd, + const llvm::DenseMap<SectionBase *, int> &Order); - std::vector<size_t> getPhdrIndices(OutputSectionCommand *Cmd); - size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName); + std::vector<size_t> getPhdrIndices(OutputSection *Sec); - MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd); + MemoryRegion *findMemoryRegion(OutputSection *Sec); void switchTo(OutputSection *Sec); uint64_t advance(uint64_t Size, unsigned Align); void output(InputSection *Sec); - void process(BaseCommand &Base); - AddressState *CurAddressState = nullptr; + void assignOffsets(OutputSection *Sec); + + // Ctx captures the local AddressState and makes it accessible + // deliberately. This is needed as there are some cases where we cannot just + // thread the current state through to a lambda function created by the + // script parser. + // This should remain a plain pointer as its lifetime is smaller than + // LinkerScript. + AddressState *Ctx = nullptr; + OutputSection *Aether; uint64_t Dot; public: - bool ErrorOnMissingSection = false; - OutputSectionCommand *createOutputSectionCommand(StringRef Name, - StringRef Location); - OutputSectionCommand *getOrCreateOutputSectionCommand(StringRef Name); + OutputSection *createOutputSection(StringRef Name, StringRef Location); + OutputSection *getOrCreateOutputSection(StringRef Name); - OutputSectionCommand *getCmd(OutputSection *Sec) const; - bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); } + bool hasPhdrsCommands() { return !PhdrsCommands.empty(); } uint64_t getDot() { return Dot; } - void discard(ArrayRef<InputSectionBase *> V); + void discard(ArrayRef<InputSection *> V); - ExprValue getSymbolValue(const Twine &Loc, StringRef S); - bool isDefined(StringRef S); + ExprValue getSymbolValue(StringRef Name, const Twine &Loc); - void fabricateDefaultCommands(); - void addOrphanSections(OutputSectionFactory &Factory); + void addOrphanSections(); void removeEmptyCommands(); void adjustSectionsBeforeSorting(); void adjustSectionsAfterSorting(); - std::vector<PhdrEntry> createPhdrs(); - bool ignoreInterpSection(); + std::vector<PhdrEntry *> createPhdrs(); + bool needsInterpSection(); bool shouldKeep(InputSectionBase *S); - void assignOffsets(OutputSectionCommand *Cmd); - void processNonSectionCommands(); void assignAddresses(); - void allocateHeaders(std::vector<PhdrEntry> &Phdrs); - void addSymbol(SymbolAssignment *Cmd); - void processCommands(OutputSectionFactory &Factory); + void allocateHeaders(std::vector<PhdrEntry *> &Phdrs); + void processSectionCommands(); + + // SECTIONS command list. + std::vector<BaseCommand *> SectionCommands; + + // PHDRS command list. + std::vector<PhdrsCommand> PhdrsCommands; + + bool HasSectionsCommand = false; + bool ErrorOnMissingSection = false; - // Parsed linker script configurations are set to this struct. - ScriptConfiguration Opt; + // List of section patterns specified with KEEP commands. They will + // be kept even if they are unused and --gc-sections is specified. + std::vector<InputSectionDescription *> KeptSections; + + // A map from memory region name to a memory region descriptor. + llvm::MapVector<llvm::StringRef, MemoryRegion *> MemoryRegions; + + // A list of symbols referenced by the script. + std::vector<llvm::StringRef> ReferencedSymbols; }; extern LinkerScript *Script; diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp index 2b2a95c47cf9..dcc829315e64 100644 --- a/ELF/MapFile.cpp +++ b/ELF/MapFile.cpp @@ -25,8 +25,9 @@ #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" -#include "Threads.h" - +#include "Symbols.h" +#include "SyntheticSections.h" +#include "lld/Common/Threads.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -35,46 +36,57 @@ using namespace llvm::object; using namespace lld; using namespace lld::elf; -typedef DenseMap<const SectionBase *, SmallVector<DefinedRegular *, 4>> - SymbolMapTy; +typedef DenseMap<const SectionBase *, SmallVector<Symbol *, 4>> SymbolMapTy; // Print out the first three columns of a line. -template <class ELFT> static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size, uint64_t Align) { - int W = ELFT::Is64Bits ? 16 : 8; + int W = Config->Is64 ? 16 : 8; OS << format("%0*llx %0*llx %5lld ", W, Addr, W, Size, Align); } static std::string indent(int Depth) { return std::string(Depth * 8, ' '); } // Returns a list of all symbols that we want to print out. -template <class ELFT> std::vector<DefinedRegular *> getSymbols() { - std::vector<DefinedRegular *> V; - for (elf::ObjectFile<ELFT> *File : Symtab<ELFT>::X->getObjectFiles()) - for (SymbolBody *B : File->getSymbols()) - if (B->File == File && !B->isSection()) - if (auto *Sym = dyn_cast<DefinedRegular>(B)) - if (Sym->Section && Sym->Section->Live) - V.push_back(Sym); +static std::vector<Symbol *> getSymbols() { + std::vector<Symbol *> V; + for (InputFile *File : ObjectFiles) { + for (Symbol *B : File->getSymbols()) { + if (auto *SS = dyn_cast<SharedSymbol>(B)) + if (SS->CopyRelSec || SS->NeedsPltAddr) + V.push_back(SS); + if (auto *DR = dyn_cast<Defined>(B)) + if (DR->File == File && !DR->isSection() && DR->Section && + DR->Section->Live) + V.push_back(DR); + } + } return V; } // Returns a map from sections to their symbols. -template <class ELFT> -SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) { +static SymbolMapTy getSectionSyms(ArrayRef<Symbol *> Syms) { SymbolMapTy Ret; - for (DefinedRegular *S : Syms) - Ret[S->Section].push_back(S); + for (Symbol *S : Syms) { + if (auto *DR = dyn_cast<Defined>(S)) { + Ret[DR->Section].push_back(S); + continue; + } + + SharedSymbol *SS = cast<SharedSymbol>(S); + if (SS->CopyRelSec) + Ret[SS->CopyRelSec].push_back(S); + else + Ret[InX::Plt].push_back(S); + } // Sort symbols by address. We want to print out symbols in the // order in the output file rather than the order they appeared // in the input files. for (auto &It : Ret) { - SmallVectorImpl<DefinedRegular *> &V = It.second; - std::sort(V.begin(), V.end(), [](DefinedRegular *A, DefinedRegular *B) { - return A->getVA() < B->getVA(); - }); + SmallVectorImpl<Symbol *> &V = It.second; + std::sort(V.begin(), V.end(), + [](Symbol *A, Symbol *B) { return A->getVA() < B->getVA(); }); } return Ret; } @@ -82,25 +94,22 @@ SymbolMapTy getSectionSyms(ArrayRef<DefinedRegular *> Syms) { // Construct a map from symbols to their stringified representations. // Demangling symbols (which is what toString() does) is slow, so // we do that in batch using parallel-for. -template <class ELFT> -DenseMap<DefinedRegular *, std::string> -getSymbolStrings(ArrayRef<DefinedRegular *> Syms) { +static DenseMap<Symbol *, std::string> +getSymbolStrings(ArrayRef<Symbol *> Syms) { std::vector<std::string> Str(Syms.size()); parallelForEachN(0, Syms.size(), [&](size_t I) { raw_string_ostream OS(Str[I]); - writeHeader<ELFT>(OS, Syms[I]->getVA(), Syms[I]->template getSize<ELFT>(), - 0); + writeHeader(OS, Syms[I]->getVA(), Syms[I]->getSize(), 0); OS << indent(2) << toString(*Syms[I]); }); - DenseMap<DefinedRegular *, std::string> Ret; + DenseMap<Symbol *, std::string> Ret; for (size_t I = 0, E = Syms.size(); I < E; ++I) Ret[Syms[I]] = std::move(Str[I]); return Ret; } -template <class ELFT> -void elf::writeMapFile(llvm::ArrayRef<OutputSectionCommand *> Script) { +void elf::writeMapFile() { if (Config->MapFile.empty()) return; @@ -113,38 +122,32 @@ void elf::writeMapFile(llvm::ArrayRef<OutputSectionCommand *> Script) { } // Collect symbol info that we want to print out. - std::vector<DefinedRegular *> Syms = getSymbols<ELFT>(); - SymbolMapTy SectionSyms = getSectionSyms<ELFT>(Syms); - DenseMap<DefinedRegular *, std::string> SymStr = getSymbolStrings<ELFT>(Syms); + std::vector<Symbol *> Syms = getSymbols(); + SymbolMapTy SectionSyms = getSectionSyms(Syms); + DenseMap<Symbol *, std::string> SymStr = getSymbolStrings(Syms); // Print out the header line. - int W = ELFT::Is64Bits ? 16 : 8; + int W = Config->Is64 ? 16 : 8; OS << left_justify("Address", W) << ' ' << left_justify("Size", W) << " Align Out In Symbol\n"; // Print out file contents. - for (OutputSectionCommand *Cmd : Script) { - OutputSection *OSec = Cmd->Sec; - writeHeader<ELFT>(OS, OSec->Addr, OSec->Size, OSec->Alignment); + for (OutputSection *OSec : OutputSections) { + writeHeader(OS, OSec->Addr, OSec->Size, OSec->Alignment); OS << OSec->Name << '\n'; // Dump symbols for each input section. - for (BaseCommand *Base : Cmd->Commands) { + for (BaseCommand *Base : OSec->SectionCommands) { auto *ISD = dyn_cast<InputSectionDescription>(Base); if (!ISD) continue; for (InputSection *IS : ISD->Sections) { - writeHeader<ELFT>(OS, OSec->Addr + IS->OutSecOff, IS->getSize(), - IS->Alignment); + writeHeader(OS, OSec->Addr + IS->OutSecOff, IS->getSize(), + IS->Alignment); OS << indent(1) << toString(IS) << '\n'; - for (DefinedRegular *Sym : SectionSyms[IS]) + for (Symbol *Sym : SectionSyms[IS]) OS << SymStr[Sym] << '\n'; } } } } - -template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSectionCommand *>); -template void elf::writeMapFile<ELF32BE>(ArrayRef<OutputSectionCommand *>); -template void elf::writeMapFile<ELF64LE>(ArrayRef<OutputSectionCommand *>); -template void elf::writeMapFile<ELF64BE>(ArrayRef<OutputSectionCommand *>); diff --git a/ELF/MapFile.h b/ELF/MapFile.h index 460848ff24d3..2d93e26d4cf8 100644 --- a/ELF/MapFile.h +++ b/ELF/MapFile.h @@ -10,13 +10,9 @@ #ifndef LLD_ELF_MAPFILE_H #define LLD_ELF_MAPFILE_H -#include <llvm/ADT/ArrayRef.h> - namespace lld { namespace elf { -struct OutputSectionCommand; -template <class ELFT> -void writeMapFile(llvm::ArrayRef<OutputSectionCommand *> Script); +void writeMapFile(); } // namespace elf } // namespace lld diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp index bde3eefc6d5f..36f994f20490 100644 --- a/ELF/MarkLive.cpp +++ b/ELF/MarkLive.cpp @@ -22,13 +22,13 @@ #include "InputSection.h" #include "LinkerScript.h" -#include "Memory.h" #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "Target.h" #include "Writer.h" +#include "lld/Common/Memory.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Object/ELF.h" #include <functional> @@ -42,15 +42,6 @@ using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; -namespace { -// A resolved relocation. The Sec and Offset fields are set if the relocation -// was resolved to an offset within a section. -struct ResolvedReloc { - InputSectionBase *Sec; - uint64_t Offset; -}; -} // end anonymous namespace - template <class ELFT> static typename ELFT::uint getAddend(InputSectionBase &Sec, const typename ELFT::Rel &Rel) { @@ -70,25 +61,36 @@ static DenseMap<StringRef, std::vector<InputSectionBase *>> CNamedSections; template <class ELFT, class RelT> static void resolveReloc(InputSectionBase &Sec, RelT &Rel, - std::function<void(ResolvedReloc)> Fn) { - SymbolBody &B = Sec.getFile<ELFT>()->getRelocTargetSym(Rel); - if (auto *D = dyn_cast<DefinedRegular>(&B)) { - if (!D->Section) + std::function<void(InputSectionBase *, uint64_t)> Fn) { + Symbol &B = Sec.getFile<ELFT>()->getRelocTargetSym(Rel); + + // If a symbol is referenced in a live section, it is used. + B.Used = true; + if (auto *SS = dyn_cast<SharedSymbol>(&B)) + if (!SS->isWeak()) + SS->getFile<ELFT>()->IsNeeded = true; + + if (auto *D = dyn_cast<Defined>(&B)) { + auto *RelSec = dyn_cast_or_null<InputSectionBase>(D->Section); + if (!RelSec) return; - typename ELFT::uint Offset = D->Value; + uint64_t Offset = D->Value; if (D->isSection()) Offset += getAddend<ELFT>(Sec, Rel); - Fn({cast<InputSectionBase>(D->Section), Offset}); - } else if (auto *U = dyn_cast<Undefined>(&B)) { - for (InputSectionBase *Sec : CNamedSections.lookup(U->getName())) - Fn({Sec, 0}); + Fn(RelSec, Offset); + return; } + + if (!B.isDefined()) + for (InputSectionBase *Sec : CNamedSections.lookup(B.getName())) + Fn(Sec, 0); } // Calls Fn for each section that Sec refers to via relocations. template <class ELFT> -static void forEachSuccessor(InputSection &Sec, - std::function<void(ResolvedReloc)> Fn) { +static void +forEachSuccessor(InputSection &Sec, + std::function<void(InputSectionBase *, uint64_t)> Fn) { if (Sec.AreRelocsRela) { for (const typename ELFT::Rela &Rel : Sec.template relas<ELFT>()) resolveReloc<ELFT>(Sec, Rel, Fn); @@ -96,8 +98,9 @@ static void forEachSuccessor(InputSection &Sec, for (const typename ELFT::Rel &Rel : Sec.template rels<ELFT>()) resolveReloc<ELFT>(Sec, Rel, Fn); } + for (InputSectionBase *IS : Sec.DependentSections) - Fn({IS, 0}); + Fn(IS, 0); } // The .eh_frame section is an unfortunate special case. @@ -115,9 +118,11 @@ static void forEachSuccessor(InputSection &Sec, // the gc pass. With that we would be able to also gc some sections holding // LSDAs and personality functions if we found that they were unused. template <class ELFT, class RelTy> -static void scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels, - std::function<void(ResolvedReloc)> Enqueue) { +static void +scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels, + std::function<void(InputSectionBase *, uint64_t)> Fn) { const endianness E = ELFT::TargetEndianness; + for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) { EhSectionPiece &Piece = EH.Pieces[I]; unsigned FirstRelI = Piece.FirstRelocation; @@ -126,31 +131,31 @@ static void scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels, if (read32<E>(Piece.data().data() + 4) == 0) { // This is a CIE, we only need to worry about the first relocation. It is // known to point to the personality function. - resolveReloc<ELFT>(EH, Rels[FirstRelI], Enqueue); + resolveReloc<ELFT>(EH, Rels[FirstRelI], Fn); continue; } // This is a FDE. The relocations point to the described function or to // a LSDA. We only need to keep the LSDA alive, so ignore anything that // points to executable sections. - typename ELFT::uint PieceEnd = Piece.InputOff + Piece.size(); + typename ELFT::uint PieceEnd = Piece.InputOff + Piece.Size; for (unsigned I2 = FirstRelI, N2 = Rels.size(); I2 < N2; ++I2) { const RelTy &Rel = Rels[I2]; if (Rel.r_offset >= PieceEnd) break; - resolveReloc<ELFT>(EH, Rels[I2], [&](ResolvedReloc R) { - if (!R.Sec || R.Sec == &InputSection::Discarded) - return; - if (R.Sec->Flags & SHF_EXECINSTR) - return; - Enqueue({R.Sec, 0}); - }); + resolveReloc<ELFT>(EH, Rels[I2], + [&](InputSectionBase *Sec, uint64_t Offset) { + if (Sec && Sec != &InputSection::Discarded && + !(Sec->Flags & SHF_EXECINSTR)) + Fn(Sec, 0); + }); } } } template <class ELFT> -static void scanEhFrameSection(EhInputSection &EH, - std::function<void(ResolvedReloc)> Enqueue) { +static void +scanEhFrameSection(EhInputSection &EH, + std::function<void(InputSectionBase *, uint64_t)> Fn) { if (!EH.NumRelocations) return; @@ -159,14 +164,14 @@ static void scanEhFrameSection(EhInputSection &EH, EH.split<ELFT>(); if (EH.AreRelocsRela) - scanEhFrameSection<ELFT>(EH, EH.template relas<ELFT>(), Enqueue); + scanEhFrameSection<ELFT>(EH, EH.template relas<ELFT>(), Fn); else - scanEhFrameSection<ELFT>(EH, EH.template rels<ELFT>(), Enqueue); + scanEhFrameSection<ELFT>(EH, EH.template rels<ELFT>(), Fn); } -// We do not garbage-collect two types of sections: -// 1) Sections used by the loader (.init, .fini, .ctors, .dtors or .jcr) -// 2) Non-allocatable sections which typically contain debugging information +// Some sections are used directly by the loader, so they should never be +// garbage-collected. This function returns true if a given section is such +// section. template <class ELFT> static bool isReserved(InputSectionBase *Sec) { switch (Sec->Type) { case SHT_FINI_ARRAY: @@ -175,9 +180,6 @@ template <class ELFT> static bool isReserved(InputSectionBase *Sec) { case SHT_PREINIT_ARRAY: return true; default: - if (!(Sec->Flags & SHF_ALLOC)) - return true; - StringRef S = Sec->Name; return S.startswith(".ctors") || S.startswith(".dtors") || S.startswith(".init") || S.startswith(".fini") || @@ -188,72 +190,74 @@ template <class ELFT> static bool isReserved(InputSectionBase *Sec) { // This is the main function of the garbage collector. // Starting from GC-root sections, this function visits all reachable // sections to set their "Live" bits. -template <class ELFT> void elf::markLive() { +template <class ELFT> static void doGcSections() { SmallVector<InputSection *, 256> Q; CNamedSections.clear(); - auto Enqueue = [&](ResolvedReloc R) { + auto Enqueue = [&](InputSectionBase *Sec, uint64_t Offset) { // Skip over discarded sections. This in theory shouldn't happen, because // the ELF spec doesn't allow a relocation to point to a deduplicated // COMDAT section directly. Unfortunately this happens in practice (e.g. // .eh_frame) so we need to add a check. - if (R.Sec == &InputSection::Discarded) + if (Sec == &InputSection::Discarded) return; - // We don't gc non alloc sections. - if (!(R.Sec->Flags & SHF_ALLOC)) - return; // Usually, a whole section is marked as live or dead, but in mergeable // (splittable) sections, each piece of data has independent liveness bit. // So we explicitly tell it which offset is in use. - if (auto *MS = dyn_cast<MergeInputSection>(R.Sec)) - MS->markLiveAt(R.Offset); + if (auto *MS = dyn_cast<MergeInputSection>(Sec)) + MS->markLiveAt(Offset); - if (R.Sec->Live) + if (Sec->Live) return; - R.Sec->Live = true; + Sec->Live = true; + // Add input section to the queue. - if (InputSection *S = dyn_cast<InputSection>(R.Sec)) + if (InputSection *S = dyn_cast<InputSection>(Sec)) Q.push_back(S); }; - auto MarkSymbol = [&](const SymbolBody *Sym) { - if (auto *D = dyn_cast_or_null<DefinedRegular>(Sym)) - if (auto *IS = cast_or_null<InputSectionBase>(D->Section)) - Enqueue({IS, D->Value}); + auto MarkSymbol = [&](Symbol *Sym) { + if (auto *D = dyn_cast_or_null<Defined>(Sym)) + if (auto *IS = dyn_cast_or_null<InputSectionBase>(D->Section)) + Enqueue(IS, D->Value); }; // Add GC root symbols. - MarkSymbol(Symtab<ELFT>::X->find(Config->Entry)); - MarkSymbol(Symtab<ELFT>::X->find(Config->Init)); - MarkSymbol(Symtab<ELFT>::X->find(Config->Fini)); + MarkSymbol(Symtab->find(Config->Entry)); + MarkSymbol(Symtab->find(Config->Init)); + MarkSymbol(Symtab->find(Config->Fini)); for (StringRef S : Config->Undefined) - MarkSymbol(Symtab<ELFT>::X->find(S)); - for (StringRef S : Script->Opt.ReferencedSymbols) - MarkSymbol(Symtab<ELFT>::X->find(S)); + MarkSymbol(Symtab->find(S)); + for (StringRef S : Script->ReferencedSymbols) + MarkSymbol(Symtab->find(S)); // Preserve externally-visible symbols if the symbols defined by this // file can interrupt other ELF file's symbols at runtime. - for (const Symbol *S : Symtab<ELFT>::X->getSymbols()) + for (Symbol *S : Symtab->getSymbols()) if (S->includeInDynsym()) - MarkSymbol(S->body()); + MarkSymbol(S); // Preserve special sections and those which are specified in linker // script KEEP command. for (InputSectionBase *Sec : InputSections) { - // .eh_frame is always marked as live now, but also it can reference to - // sections that contain personality. We preserve all non-text sections - // referred by .eh_frame here. - if (auto *EH = dyn_cast_or_null<EhInputSection>(Sec)) + // Mark .eh_frame sections as live because there are usually no relocations + // that point to .eh_frames. Otherwise, the garbage collector would drop + // all of them. We also want to preserve personality routines and LSDA + // referenced by .eh_frame sections, so we scan them for that here. + if (auto *EH = dyn_cast_or_null<EhInputSection>(Sec)) { + EH->Live = true; scanEhFrameSection<ELFT>(*EH, Enqueue); + } + if (Sec->Flags & SHF_LINK_ORDER) continue; if (isReserved<ELFT>(Sec) || Script->shouldKeep(Sec)) - Enqueue({Sec, 0}); + Enqueue(Sec, 0); else if (isValidCIdentifier(Sec->Name)) { CNamedSections[Saver.save("__start_" + Sec->Name)].push_back(Sec); - CNamedSections[Saver.save("__end_" + Sec->Name)].push_back(Sec); + CNamedSections[Saver.save("__stop_" + Sec->Name)].push_back(Sec); } } @@ -262,6 +266,49 @@ template <class ELFT> void elf::markLive() { forEachSuccessor<ELFT>(*Q.pop_back_val(), Enqueue); } +// Before calling this function, Live bits are off for all +// input sections. This function make some or all of them on +// so that they are emitted to the output file. +template <class ELFT> void elf::markLive() { + // If -gc-sections is missing, no sections are removed. + if (!Config->GcSections) { + for (InputSectionBase *Sec : InputSections) + Sec->Live = true; + return; + } + + // The -gc-sections option works only for SHF_ALLOC sections + // (sections that are memory-mapped at runtime). So we can + // unconditionally make non-SHF_ALLOC sections alive. + // + // Non SHF_ALLOC sections are not removed even if they are + // unreachable through relocations because reachability is not + // a good signal whether they are garbage or not (e.g. there is + // usually no section referring to a .comment section, but we + // want to keep it.) + // + // Note on SHF_REL{,A}: Such sections reach here only when -r + // or -emit-reloc were given. And they are subject of garbage + // collection because, if we remove a text section, we also + // remove its relocation section. + for (InputSectionBase *Sec : InputSections) { + bool IsAlloc = (Sec->Flags & SHF_ALLOC); + bool IsRel = (Sec->Type == SHT_REL || Sec->Type == SHT_RELA); + if (!IsAlloc && !IsRel) + Sec->Live = true; + } + + // Follow the graph to mark all live sections. + doGcSections<ELFT>(); + + // Report garbage-collected sections. + if (Config->PrintGcSections) + for (InputSectionBase *Sec : InputSections) + if (!Sec->Live) + message("removing unused section from '" + Sec->Name + "' in file '" + + Sec->File->getName() + "'"); +} + template void elf::markLive<ELF32LE>(); template void elf::markLive<ELF32BE>(); template void elf::markLive<ELF64LE>(); diff --git a/ELF/Memory.h b/ELF/Memory.h deleted file mode 100644 index 4000f2f9f1c9..000000000000 --- a/ELF/Memory.h +++ /dev/null @@ -1,67 +0,0 @@ -//===- Memory.h -------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines arena allocators. -// -// Almost all large objects, such as files, sections or symbols, are -// used for the entire lifetime of the linker once they are created. -// This usage characteristic makes arena allocator an attractive choice -// where the entire linker is one arena. With an arena, newly created -// objects belong to the arena and freed all at once when everything is done. -// Arena allocators are efficient and easy to understand. -// Most objects are allocated using the arena allocators defined by this file. -// -// If you edit this file, please edit COFF/Memory.h too. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_ELF_MEMORY_H -#define LLD_ELF_MEMORY_H - -#include "llvm/Support/Allocator.h" -#include "llvm/Support/StringSaver.h" -#include <vector> - -namespace lld { -namespace elf { - -// Use this arena if your object doesn't have a destructor. -extern llvm::BumpPtrAllocator BAlloc; -extern llvm::StringSaver Saver; - -// These two classes are hack to keep track of all -// SpecificBumpPtrAllocator instances. -struct SpecificAllocBase { - SpecificAllocBase() { Instances.push_back(this); } - virtual ~SpecificAllocBase() = default; - virtual void reset() = 0; - static std::vector<SpecificAllocBase *> Instances; -}; - -template <class T> struct SpecificAlloc : public SpecificAllocBase { - void reset() override { Alloc.DestroyAll(); } - llvm::SpecificBumpPtrAllocator<T> Alloc; -}; - -// Use this arena if your object has a destructor. -// Your destructor will be invoked from freeArena(). -template <typename T, typename... U> T *make(U &&... Args) { - static SpecificAlloc<T> Alloc; - return new (Alloc.Alloc.Allocate()) T(std::forward<U>(Args)...); -} - -inline void freeArena() { - for (SpecificAllocBase *Alloc : SpecificAllocBase::Instances) - Alloc->reset(); - BAlloc.Reset(); -} -} // namespace elf -} // namespace lld - -#endif diff --git a/ELF/Options.td b/ELF/Options.td index 1400a206bdfc..20027e90aefd 100644 --- a/ELF/Options.td +++ b/ELF/Options.td @@ -5,7 +5,11 @@ include "llvm/Option/OptParser.td" class F<string name>: Flag<["--", "-"], name>; class J<string name>: Joined<["--", "-"], name>; class S<string name>: Separate<["--", "-"], name>; -class JS<string name>: JoinedOrSeparate<["--", "-"], name>; + +multiclass Eq<string name> { + def "": Separate<["--", "-"], name>; + def _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>; +} def auxiliary: S<"auxiliary">, HelpText<"Set DT_AUXILIARY field to the specified name">; @@ -22,21 +26,24 @@ def build_id: F<"build-id">, HelpText<"Generate build ID note">; def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">; -def compress_debug_sections : J<"compress-debug-sections=">, +defm compress_debug_sections : Eq<"compress-debug-sections">, HelpText<"Compress DWARF debug sections">; -def defsym: J<"defsym=">, HelpText<"Define a symbol alias">; +defm defsym: Eq<"defsym">, HelpText<"Define a symbol alias">; -def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">, - HelpText<"Add a directory to the library search path">; +defm library_path: Eq<"library-path">, + HelpText<"Add a directory to the library search path">, MetaVarName<"<dir>">; -def O: Joined<["-"], "O">, HelpText<"Optimize output file size">; +def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">; -def Tbss: S<"Tbss">, HelpText<"Same as --section-start with .bss as the sectionname">; +defm Tbss: Eq<"Tbss">, + HelpText<"Same as --section-start with .bss as the sectionname">; -def Tdata: S<"Tdata">, HelpText<"Same as --section-start with .data as the sectionname">; +defm Tdata: Eq<"Tdata">, + HelpText<"Same as --section-start with .data as the sectionname">; -def Ttext: S<"Ttext">, HelpText<"Same as --section-start with .text as the sectionname">; +defm Ttext: Eq<"Ttext">, + HelpText<"Same as --section-start with .text as the sectionname">; def allow_multiple_definition: F<"allow-multiple-definition">, HelpText<"Allow multiple definitions">; @@ -44,6 +51,9 @@ def allow_multiple_definition: F<"allow-multiple-definition">, def as_needed: F<"as-needed">, HelpText<"Only set DT_NEEDED for shared libraries if used">; +// -chroot doesn't have a help text because it is an internal option. +def chroot: S<"chroot">; + def color_diagnostics: F<"color-diagnostics">, HelpText<"Use colors in diagnostics">; @@ -69,7 +79,7 @@ def discard_none: F<"discard-none">, def dynamic_linker: S<"dynamic-linker">, HelpText<"Which dynamic linker to use">; -def dynamic_list: S<"dynamic-list">, +defm dynamic_list: Eq<"dynamic-list">, HelpText<"Read a list of dynamic symbols">; def eh_frame_hdr: F<"eh-frame-hdr">, @@ -83,37 +93,42 @@ def enable_new_dtags: F<"enable-new-dtags">, def end_lib: F<"end-lib">, HelpText<"End a grouping of objects that should be treated as if they were together in an archive">; -def entry: S<"entry">, MetaVarName<"<entry>">, - HelpText<"Name of entry point symbol">; +defm entry: Eq<"entry">, HelpText<"Name of entry point symbol">, + MetaVarName<"<entry>">; -def error_limit: S<"error-limit">, +defm error_limit: Eq<"error-limit">, HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">; def error_unresolved_symbols: F<"error-unresolved-symbols">, HelpText<"Report unresolved symbols as errors">; -def exclude_libs: S<"exclude-libs">, +defm exclude_libs: Eq<"exclude-libs">, HelpText<"Exclude static libraries from automatic export">; def export_dynamic: F<"export-dynamic">, HelpText<"Put symbols in the dynamic symbol table">; -def export_dynamic_symbol: S<"export-dynamic-symbol">, +defm export_dynamic_symbol: Eq<"export-dynamic-symbol">, HelpText<"Put a symbol in the dynamic symbol table">; def fatal_warnings: F<"fatal-warnings">, HelpText<"Treat warnings as errors">; -def filter: J<"filter=">, HelpText<"Set DT_FILTER field to the specified name">; +defm filter: Eq<"filter">, + HelpText<"Set DT_FILTER field to the specified name">; -def fini: S<"fini">, MetaVarName<"<symbol>">, - HelpText<"Specify a finalizer function">; +defm fini: Eq<"fini">, + HelpText<"Specify a finalizer function">, MetaVarName<"<symbol>">; + +def fix_cortex_a53_843419: F<"fix-cortex-a53-843419">, + HelpText<"Apply fixes for AArch64 Cortex-A53 erratum 843419">; def full_shutdown : F<"full-shutdown">, HelpText<"Perform a full shutdown instead of calling _exit">; -def format: J<"format=">, MetaVarName<"<input-format>">, - HelpText<"Change the input format of the inputs following this option">; +defm format: Eq<"format">, + HelpText<"Change the input format of the inputs following this option">, + MetaVarName<"<input-format>">; def gc_sections: F<"gc-sections">, HelpText<"Enable garbage collection of unused sections">; @@ -121,29 +136,35 @@ def gc_sections: F<"gc-sections">, def gdb_index: F<"gdb-index">, HelpText<"Generate .gdb_index section">; -def hash_style: S<"hash-style">, +defm hash_style: Eq<"hash-style">, HelpText<"Specify hash style (sysv, gnu or both)">; def help: F<"help">, HelpText<"Print option help">; def icf_all: F<"icf=all">, HelpText<"Enable identical code folding">; +def icf_data: F<"icf-data">, + HelpText<"Enable ICF to also fold identical read only data">; + def icf_none: F<"icf=none">, HelpText<"Disable identical code folding">; -def image_base : J<"image-base=">, HelpText<"Set the base address">; +defm image_base : Eq<"image-base">, HelpText<"Set the base address">; -def init: S<"init">, MetaVarName<"<symbol>">, - HelpText<"Specify an initializer function">; +defm init: Eq<"init">, HelpText<"Specify an initializer function">, + MetaVarName<"<symbol>">; -def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">, - HelpText<"Root name of library to use">; +defm library: Eq<"library">, HelpText<"Root name of library to use">, + MetaVarName<"<libName>">; def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">, HelpText<"Optimization level for LTO">; def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">; -def Map: JS<"Map">, HelpText<"Print a link map to the specified file">; +defm Map: Eq<"Map">, HelpText<"Print a link map to the specified file">; + +def merge_exidx_entries: F<"merge-exidx-entries">, + HelpText<"Enable merging .ARM.exidx entries">; def nostdlib: F<"nostdlib">, HelpText<"Only search directories specified on the command line">; @@ -163,15 +184,24 @@ def no_demangle: F<"no-demangle">, def no_dynamic_linker: F<"no-dynamic-linker">, HelpText<"Inhibit output of .interp section">; +def no_eh_frame_hdr: F<"no-eh-frame-hdr">, + HelpText<"Do not create .eh_frame_hdr section">; + def no_export_dynamic: F<"no-export-dynamic">; def no_fatal_warnings: F<"no-fatal-warnings">; def no_gc_sections: F<"no-gc-sections">, HelpText<"Disable garbage collection of unused sections">; +def no_gdb_index: F<"no-gdb-index">, + HelpText<"Do not generate .gdb_index section">; + def no_gnu_unique: F<"no-gnu-unique">, HelpText<"Disable STB_GNU_UNIQUE symbol binding">; +def no_merge_exidx_entries: F<"no-merge-exidx-entries">, + HelpText<"Disable merging .ARM.exidx entries">; + def no_threads: F<"no-threads">, HelpText<"Do not run the linker multi-threaded">; @@ -183,7 +213,14 @@ def noinhibit_exec: F<"noinhibit-exec">, def nopie: F<"nopie">, HelpText<"Do not create a position independent executable">; -def no_rosegment: F<"no-rosegment">, HelpText<"Do not put read-only non-executable sections in their own segment">; +def no_omagic: Flag<["--"], "no-omagic">, MetaVarName<"<magic>">, + HelpText<"Do not set the text data sections to be writable">; + +def no_print_gc_sections: F<"no-print-gc-sections">, + HelpText<"Do not list removed unused sections">; + +def no_rosegment: F<"no-rosegment">, + HelpText<"Do not put read-only non-executable sections in their own segment">; def no_undefined: F<"no-undefined">, HelpText<"Report unresolved symbols even if the linker is creating a shared library">; @@ -200,6 +237,12 @@ def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">, def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">, HelpText<"Set the text and data sections to be readable and writable">; +defm orphan_handling: Eq<"orphan-handling">, + HelpText<"Control how orphan sections are handled when linker script used">; + +def pack_dyn_relocs_eq: J<"pack-dyn-relocs=">, MetaVarName<"<format>">, + HelpText<"Pack dynamic relocations in the given format (none or android)">; + def pie: F<"pie">, HelpText<"Create a position independent executable">; def print_gc_sections: F<"print-gc-sections">, @@ -208,26 +251,28 @@ def print_gc_sections: F<"print-gc-sections">, def print_map: F<"print-map">, HelpText<"Print a link map to the standard output">; -def reproduce: S<"reproduce">, +defm reproduce: Eq<"reproduce">, HelpText<"Dump linker invocation and input files for debugging">; -def rpath: S<"rpath">, HelpText<"Add a DT_RUNPATH to the output">; +defm rpath: Eq<"rpath">, HelpText<"Add a DT_RUNPATH to the output">; def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">; -def retain_symbols_file: J<"retain-symbols-file=">, MetaVarName<"<file>">, - HelpText<"Retain only the symbols listed in the file">; +defm retain_symbols_file: Eq<"retain-symbols-file">, + HelpText<"Retain only the symbols listed in the file">, + MetaVarName<"<file>">; -def script: S<"script">, HelpText<"Read linker script">; +defm script: Eq<"script">, HelpText<"Read linker script">; def section_start: S<"section-start">, MetaVarName<"<address>">, HelpText<"Set address of section">; def shared: F<"shared">, HelpText<"Build a shared object">; -def soname: J<"soname=">, HelpText<"Set DT_SONAME">; +defm soname: Eq<"soname">, HelpText<"Set DT_SONAME">; -def sort_section: S<"sort-section">, HelpText<"Specifies sections sorting rule when linkerscript is used">; +defm sort_section: Eq<"sort-section">, + HelpText<"Specifies sections sorting rule when linkerscript is used">; def start_lib: F<"start-lib">, HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">; @@ -239,27 +284,29 @@ def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">; def symbol_ordering_file: S<"symbol-ordering-file">, HelpText<"Layout sections in the order specified by symbol file">; -def sysroot: J<"sysroot=">, HelpText<"Set the system root">; +defm sysroot: Eq<"sysroot">, HelpText<"Set the system root">; def target1_rel: F<"target1-rel">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">; def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32">; -def target2: J<"target2=">, MetaVarName<"<type>">, HelpText<"Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">; +defm target2: Eq<"target2">, + HelpText<"Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">, + MetaVarName<"<type>">; def threads: F<"threads">, HelpText<"Run the linker multi-threaded">; def trace: F<"trace">, HelpText<"Print the names of the input files">; -def trace_symbol : S<"trace-symbol">, HelpText<"Trace references to symbols">; +defm trace_symbol : Eq<"trace-symbol">, HelpText<"Trace references to symbols">; -def undefined: S<"undefined">, +defm undefined: Eq<"undefined">, HelpText<"Force undefined symbol during linking">; -def unresolved_symbols: J<"unresolved-symbols=">, +defm unresolved_symbols: Eq<"unresolved-symbols">, HelpText<"Determine how to handle unresolved symbols">; -def rsp_quoting: J<"rsp-quoting=">, +defm rsp_quoting: Eq<"rsp-quoting">, HelpText<"Quoting style for response files. Values supported: windows|posix">; def v: Flag<["-"], "v">, HelpText<"Display the version number">; @@ -268,8 +315,7 @@ def verbose: F<"verbose">, HelpText<"Verbose mode">; def version: F<"version">, HelpText<"Display the version number and exit">; -def version_script: S<"version-script">, - HelpText<"Read a version script">; +defm version_script: Eq<"version-script">, HelpText<"Read a version script">; def warn_common: F<"warn-common">, HelpText<"Warn about duplicate common symbols">; @@ -280,8 +326,8 @@ def warn_unresolved_symbols: F<"warn-unresolved-symbols">, def whole_archive: F<"whole-archive">, HelpText<"Force load of all members in a static library">; -def wrap: S<"wrap">, MetaVarName<"<symbol>">, - HelpText<"Use wrapper functions for symbol">; +defm wrap: Eq<"wrap">, HelpText<"Use wrapper functions for symbol">, + MetaVarName<"<symbol>">; def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">, HelpText<"Linker option extensions">; @@ -293,60 +339,36 @@ def alias_Bdynamic_dy: F<"dy">, Alias<Bdynamic>; def alias_Bstatic_dn: F<"dn">, Alias<Bstatic>; def alias_Bstatic_non_shared: F<"non_shared">, Alias<Bstatic>; def alias_Bstatic_static: F<"static">, Alias<Bstatic>; -def alias_L__library_path: J<"library-path=">, Alias<L>; def alias_define_common_d: Flag<["-"], "d">, Alias<define_common>; def alias_define_common_dc: F<"dc">, Alias<define_common>; def alias_define_common_dp: F<"dp">, Alias<define_common>; -def alias_defsym: S<"defsym">, Alias<defsym>; def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>; def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>; -def alias_dynamic_list: J<"dynamic-list=">, Alias<dynamic_list>; def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>; def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>; -def alias_entry_entry: J<"entry=">, Alias<entry>; -def alias_error_limit: J<"error-limit=">, Alias<error_limit>; -def alias_exclude_libs: J<"exclude-libs=">, Alias<exclude_libs>; def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>; -def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">, - Alias<export_dynamic_symbol>; def alias_filter: Separate<["-"], "F">, Alias<filter>; -def alias_fini_fini: J<"fini=">, Alias<fini>; def alias_format_b: S<"b">, Alias<format>; -def alias_hash_style_hash_style: J<"hash-style=">, Alias<hash_style>; -def alias_init_init: J<"init=">, Alias<init>; -def alias_l__library: J<"library=">, Alias<l>; -def alias_Map_eq: J<"Map=">, Alias<Map>; +def alias_library: JoinedOrSeparate<["-"], "l">, Alias<library>; +def alias_library_path: JoinedOrSeparate<["-"], "L">, Alias<library_path>; def alias_omagic: Flag<["-"], "N">, Alias<omagic>; def alias_o_output: Joined<["--"], "output=">, Alias<o>; def alias_o_output2 : Separate<["--"], "output">, Alias<o>; def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>; def alias_print_map_M: Flag<["-"], "M">, Alias<print_map>; def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>; -def alias_reproduce_eq: J<"reproduce=">, Alias<reproduce>; -def alias_retain_symbols_file: S<"retain-symbols-file">, Alias<retain_symbols_file>; def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>; -def alias_rpath_rpath: J<"rpath=">, Alias<rpath>; def alias_script_T: JoinedOrSeparate<["-"], "T">, Alias<script>; def alias_shared_Bshareable: F<"Bshareable">, Alias<shared>; def alias_soname_h: JoinedOrSeparate<["-"], "h">, Alias<soname>; -def alias_soname_soname: S<"soname">, Alias<soname>; -def alias_sort_section: J<"sort-section=">, Alias<sort_section>; -def alias_script: J<"script=">, Alias<script>; def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>; def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>; -def alias_Tbss: J<"Tbss=">, Alias<Tbss>; -def alias_Tdata: J<"Tdata=">, Alias<Tdata>; def alias_trace: Flag<["-"], "t">, Alias<trace>; -def trace_trace_symbol_eq : J<"trace-symbol=">, Alias<trace_symbol>; def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>; -def alias_Ttext: J<"Ttext=">, Alias<Ttext>; def alias_Ttext_segment: S<"Ttext-segment">, Alias<Ttext>; def alias_Ttext_segment_eq: J<"Ttext-segment=">, Alias<Ttext>; -def alias_undefined_eq: J<"undefined=">, Alias<undefined>; def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>; -def alias_version_script_eq: J<"version-script=">, Alias<version_script>; def alias_version_V: Flag<["-"], "V">, Alias<version>; -def alias_wrap_wrap: J<"wrap=">, Alias<wrap>; // Our symbol resolution algorithm handles symbols in archive files differently // than traditional linkers, so we don't need --start-group and --end-group. @@ -369,6 +391,8 @@ def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">, HelpText<"YAML output file for optimization remarks">; def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">, HelpText<"Include hotness informations in the optimization remarks file">; +defm plugin_opt: Eq<"plugin-opt">, + HelpText<"specifies LTO options for compatibility with GNU linkers">; def save_temps: F<"save-temps">; def thinlto_cache_dir: J<"thinlto-cache-dir=">, HelpText<"Path to ThinLTO cached object file directory">; @@ -385,18 +409,17 @@ def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">; // --version output. def plugin: S<"plugin">; def plugin_eq: J<"plugin=">; -def plugin_opt: S<"plugin-opt">; -def plugin_opt_eq: J<"plugin-opt=">; // Options listed below are silently ignored for now for compatibility. def allow_shlib_undefined: F<"allow-shlib-undefined">; -def cref: Flag<["--"], "cref">; +def cref: F<"cref">; def detect_odr_violations: F<"detect-odr-violations">; def g: Flag<["-"], "g">; +def long_plt: F<"long-plt">; def no_add_needed: F<"no-add-needed">; def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">; -def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">, - Alias<no_add_needed>; +def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">; +def no_ctors_in_init_array: F<"no-ctors-in-init-array">; def no_keep_memory: F<"no-keep-memory">; def no_mmap_output_file: F<"no-mmap-output-file">; def no_warn_common: F<"no-warn-common">; @@ -406,9 +429,9 @@ def rpath_link_eq: J<"rpath-link=">; def sort_common: F<"sort-common">; def stats: F<"stats">; def warn_execstack: F<"warn-execstack">; +def warn_once: F<"warn-once">; def warn_shared_textrel: F<"warn-shared-textrel">; def EB : F<"EB">; def EL : F<"EL">; def G: JoinedOrSeparate<["-"], "G">; def Qy : F<"Qy">; - diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index abe548165866..f0677f7e1ca5 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -10,13 +10,14 @@ #include "OutputSections.h" #include "Config.h" #include "LinkerScript.h" -#include "Memory.h" #include "Strings.h" #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" -#include "Threads.h" +#include "lld/Common/Memory.h" +#include "lld/Common/Threads.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SHA1.h" @@ -42,7 +43,6 @@ OutputSection *Out::InitArray; OutputSection *Out::FiniArray; std::vector<OutputSection *> elf::OutputSections; -std::vector<OutputSectionCommand *> elf::OutputSectionCommands; uint32_t OutputSection::getPhdrFlags() const { uint32_t Ret = PF_R; @@ -68,210 +68,376 @@ void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) { } OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags) - : SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type, + : BaseCommand(OutputSectionKind), + SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type, /*Info*/ 0, /*Link*/ 0), - SectionIndex(INT_MAX) {} + SectionIndex(INT_MAX) { + Live = false; +} -static uint64_t updateOffset(uint64_t Off, InputSection *S) { - Off = alignTo(Off, S->Alignment); - S->OutSecOff = Off; - return Off + S->getSize(); +// We allow sections of types listed below to merged into a +// single progbits section. This is typically done by linker +// scripts. Merging nobits and progbits will force disk space +// to be allocated for nobits sections. Other ones don't require +// any special treatment on top of progbits, so there doesn't +// seem to be a harm in merging them. +static bool canMergeToProgbits(unsigned Type) { + return Type == SHT_NOBITS || Type == SHT_PROGBITS || Type == SHT_INIT_ARRAY || + Type == SHT_PREINIT_ARRAY || Type == SHT_FINI_ARRAY || + Type == SHT_NOTE; } -void OutputSection::addSection(InputSection *S) { - assert(S->Live); - Sections.push_back(S); - S->Parent = this; - this->updateAlignment(S->Alignment); +void OutputSection::addSection(InputSection *IS) { + if (!Live) { + // If IS is the first section to be added to this section, + // initialize Type and Entsize from IS. + Live = true; + Type = IS->Type; + Entsize = IS->Entsize; + } else { + // Otherwise, check if new type or flags are compatible with existing ones. + if ((Flags & (SHF_ALLOC | SHF_TLS)) != (IS->Flags & (SHF_ALLOC | SHF_TLS))) + error("incompatible section flags for " + Name + "\n>>> " + toString(IS) + + ": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Name + + ": 0x" + utohexstr(Flags)); + + if (Type != IS->Type) { + if (!canMergeToProgbits(Type) || !canMergeToProgbits(IS->Type)) + error("section type mismatch for " + IS->Name + "\n>>> " + + toString(IS) + ": " + + getELFSectionTypeName(Config->EMachine, IS->Type) + + "\n>>> output section " + Name + ": " + + getELFSectionTypeName(Config->EMachine, Type)); + Type = SHT_PROGBITS; + } + } - // The actual offsets will be computed by assignAddresses. For now, use - // crude approximation so that it is at least easy for other code to know the - // section order. It is also used to calculate the output section size early - // for compressed debug sections. - this->Size = updateOffset(Size, S); + IS->Parent = this; + Flags |= IS->Flags; + Alignment = std::max(Alignment, IS->Alignment); + IS->OutSecOff = Size++; // If this section contains a table of fixed-size entries, sh_entsize - // holds the element size. Consequently, if this contains two or more - // input sections, all of them must have the same sh_entsize. However, - // you can put different types of input sections into one output - // sectin by using linker scripts. I don't know what to do here. - // Probably we sholuld handle that as an error. But for now we just - // pick the largest sh_entsize. - this->Entsize = std::max(this->Entsize, S->Entsize); + // holds the element size. If it contains elements of different size we + // set sh_entsize to 0. + if (Entsize != IS->Entsize) + Entsize = 0; + + if (!IS->Assigned) { + IS->Assigned = true; + if (SectionCommands.empty() || + !isa<InputSectionDescription>(SectionCommands.back())) + SectionCommands.push_back(make<InputSectionDescription>("")); + auto *ISD = cast<InputSectionDescription>(SectionCommands.back()); + ISD->Sections.push_back(IS); + } } -static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) { - // The ELF spec just says - // ---------------------------------------------------------------- - // In the first phase, input sections that match in name, type and - // attribute flags should be concatenated into single sections. - // ---------------------------------------------------------------- - // - // However, it is clear that at least some flags have to be ignored for - // section merging. At the very least SHF_GROUP and SHF_COMPRESSED have to be - // ignored. We should not have two output .text sections just because one was - // in a group and another was not for example. - // - // It also seems that that wording was a late addition and didn't get the - // necessary scrutiny. - // - // Merging sections with different flags is expected by some users. One - // reason is that if one file has - // - // int *const bar __attribute__((section(".foo"))) = (int *)0; - // - // gcc with -fPIC will produce a read only .foo section. But if another - // file has - // - // int zed; - // int *const bar __attribute__((section(".foo"))) = (int *)&zed; - // - // gcc with -fPIC will produce a read write section. - // - // Last but not least, when using linker script the merge rules are forced by - // the script. Unfortunately, linker scripts are name based. This means that - // expressions like *(.foo*) can refer to multiple input sections with - // different flags. We cannot put them in different output sections or we - // would produce wrong results for - // - // start = .; *(.foo.*) end = .; *(.bar) - // - // and a mapping of .foo1 and .bar1 to one section and .foo2 and .bar2 to - // another. The problem is that there is no way to layout those output - // sections such that the .foo sections are the only thing between the start - // and end symbols. - // - // Given the above issues, we instead merge sections by name and error on - // incompatible types and flags. - - uint32_t Alignment = 0; - uint64_t Flags = 0; - if (Config->Relocatable && (C->Flags & SHF_MERGE)) { - Alignment = std::max<uint64_t>(C->Alignment, C->Entsize); - Flags = C->Flags & (SHF_MERGE | SHF_STRINGS); - } +void elf::sortByOrder(MutableArrayRef<InputSection *> In, + std::function<int(InputSectionBase *S)> Order) { + typedef std::pair<int, InputSection *> Pair; + auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; + + std::vector<Pair> V; + for (InputSection *S : In) + V.push_back({Order(S), S}); + std::stable_sort(V.begin(), V.end(), Comp); - return SectionKey{OutsecName, Flags, Alignment}; + for (size_t I = 0; I < V.size(); ++I) + In[I] = V[I].second; } -OutputSectionFactory::OutputSectionFactory() {} +uint64_t elf::getHeaderSize() { + if (Config->OFormatBinary) + return 0; + return Out::ElfHeader->Size + Out::ProgramHeaders->Size; +} -static uint64_t getIncompatibleFlags(uint64_t Flags) { - return Flags & (SHF_ALLOC | SHF_TLS); +bool OutputSection::classof(const BaseCommand *C) { + return C->Kind == OutputSectionKind; } -// We allow sections of types listed below to merged into a -// single progbits section. This is typically done by linker -// scripts. Merging nobits and progbits will force disk space -// to be allocated for nobits sections. Other ones don't require -// any special treatment on top of progbits, so there doesn't -// seem to be a harm in merging them. -static bool canMergeToProgbits(unsigned Type) { - return Type == SHT_NOBITS || Type == SHT_PROGBITS || Type == SHT_INIT_ARRAY || - Type == SHT_PREINIT_ARRAY || Type == SHT_FINI_ARRAY || - Type == SHT_NOTE; +void OutputSection::sort(std::function<int(InputSectionBase *S)> Order) { + assert(Live); + assert(SectionCommands.size() == 1); + sortByOrder(cast<InputSectionDescription>(SectionCommands[0])->Sections, + Order); } -void elf::reportDiscarded(InputSectionBase *IS) { - if (!Config->PrintGcSections) - return; - message("removing unused section from '" + IS->Name + "' in file '" + - IS->File->getName() + "'"); +// Fill [Buf, Buf + Size) with Filler. +// This is used for linker script "=fillexp" command. +static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) { + size_t I = 0; + for (; I + 4 < Size; I += 4) + memcpy(Buf + I, &Filler, 4); + memcpy(Buf + I, &Filler, Size - I); } -void OutputSectionFactory::addInputSec(InputSectionBase *IS, - StringRef OutsecName) { - // Sections with the SHT_GROUP attribute reach here only when the - r option - // is given. Such sections define "section groups", and InputFiles.cpp has - // dedup'ed section groups by their signatures. For the -r, we want to pass - // through all SHT_GROUP sections without merging them because merging them - // creates broken section contents. - if (IS->Type == SHT_GROUP) { - OutputSection *Out = nullptr; - addInputSec(IS, OutsecName, Out); - return; - } +// Compress section contents if this section contains debug info. +template <class ELFT> void OutputSection::maybeCompress() { + typedef typename ELFT::Chdr Elf_Chdr; - // Imagine .zed : { *(.foo) *(.bar) } script. Both foo and bar may have - // relocation sections .rela.foo and .rela.bar for example. Most tools do - // not allow multiple REL[A] sections for output section. Hence we - // should combine these relocation sections into single output. - // We skip synthetic sections because it can be .rela.dyn/.rela.plt or any - // other REL[A] sections created by linker itself. - if (!isa<SyntheticSection>(IS) && - (IS->Type == SHT_REL || IS->Type == SHT_RELA)) { - auto *Sec = cast<InputSection>(IS); - OutputSection *Out = Sec->getRelocatedSection()->getOutputSection(); - addInputSec(IS, OutsecName, Out->RelocationSection); + // Compress only DWARF debug sections. + if (!Config->CompressDebugSections || (Flags & SHF_ALLOC) || + !Name.startswith(".debug_")) return; - } - SectionKey Key = createKey(IS, OutsecName); - OutputSection *&Sec = Map[Key]; - addInputSec(IS, OutsecName, Sec); + // Calculate the section offsets and size pre-compression. + Size = 0; + for (BaseCommand *Cmd : SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd)) + for (InputSection *IS : ISD->Sections) { + IS->OutSecOff = alignTo(Size, IS->Alignment); + this->Size = IS->OutSecOff + IS->getSize(); + } + + // Create a section header. + ZDebugHeader.resize(sizeof(Elf_Chdr)); + auto *Hdr = reinterpret_cast<Elf_Chdr *>(ZDebugHeader.data()); + Hdr->ch_type = ELFCOMPRESS_ZLIB; + Hdr->ch_size = Size; + Hdr->ch_addralign = Alignment; + + // Write section contents to a temporary buffer and compress it. + std::vector<uint8_t> Buf(Size); + writeTo<ELFT>(Buf.data()); + if (Error E = zlib::compress(toStringRef(Buf), CompressedData)) + fatal("compress failed: " + llvm::toString(std::move(E))); + + // Update section headers. + Size = sizeof(Elf_Chdr) + CompressedData.size(); + Flags |= SHF_COMPRESSED; } -void OutputSectionFactory::addInputSec(InputSectionBase *IS, - StringRef OutsecName, - OutputSection *&Sec) { - if (!IS->Live) { - reportDiscarded(IS); +static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { + if (Size == 1) + *Buf = Data; + else if (Size == 2) + write16(Buf, Data, Config->Endianness); + else if (Size == 4) + write32(Buf, Data, Config->Endianness); + else if (Size == 8) + write64(Buf, Data, Config->Endianness); + else + llvm_unreachable("unsupported Size argument"); +} + +template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) { + if (Type == SHT_NOBITS) + return; + + Loc = Buf; + + // If -compress-debug-section is specified and if this is a debug seciton, + // we've already compressed section contents. If that's the case, + // just write it down. + if (!CompressedData.empty()) { + memcpy(Buf, ZDebugHeader.data(), ZDebugHeader.size()); + memcpy(Buf + ZDebugHeader.size(), CompressedData.data(), + CompressedData.size()); return; } - if (Sec) { - if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags)) - error("incompatible section flags for " + Sec->Name + "\n>>> " + - toString(IS) + ": 0x" + utohexstr(IS->Flags) + - "\n>>> output section " + Sec->Name + ": 0x" + - utohexstr(Sec->Flags)); - if (Sec->Type != IS->Type) { - if (canMergeToProgbits(Sec->Type) && canMergeToProgbits(IS->Type)) - Sec->Type = SHT_PROGBITS; + // Write leading padding. + std::vector<InputSection *> Sections; + for (BaseCommand *Cmd : SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd)) + for (InputSection *IS : ISD->Sections) + if (IS->Live) + Sections.push_back(IS); + uint32_t Filler = getFiller(); + if (Filler) + fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler); + + parallelForEachN(0, Sections.size(), [&](size_t I) { + InputSection *IS = Sections[I]; + IS->writeTo<ELFT>(Buf); + + // Fill gaps between sections. + if (Filler) { + uint8_t *Start = Buf + IS->OutSecOff + IS->getSize(); + uint8_t *End; + if (I + 1 == Sections.size()) + End = Buf + Size; else - error("section type mismatch for " + IS->Name + "\n>>> " + - toString(IS) + ": " + - getELFSectionTypeName(Config->EMachine, IS->Type) + - "\n>>> output section " + Sec->Name + ": " + - getELFSectionTypeName(Config->EMachine, Sec->Type)); + End = Buf + Sections[I + 1]->OutSecOff; + fill(Start, End - Start, Filler); } - Sec->Flags |= IS->Flags; - } else { - Sec = make<OutputSection>(OutsecName, IS->Type, IS->Flags); - OutputSections.push_back(Sec); + }); + + // Linker scripts may have BYTE()-family commands with which you + // can write arbitrary bytes to the output. Process them if any. + for (BaseCommand *Base : SectionCommands) + if (auto *Data = dyn_cast<ByteCommand>(Base)) + writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); +} + +template <class ELFT> +static void finalizeShtGroup(OutputSection *OS, + InputSection *Section) { + assert(Config->Relocatable); + + // sh_link field for SHT_GROUP sections should contain the section index of + // the symbol table. + OS->Link = InX::SymTab->getParent()->SectionIndex; + + // sh_info then contain index of an entry in symbol table section which + // provides signature of the section group. + ObjFile<ELFT> *Obj = Section->getFile<ELFT>(); + ArrayRef<Symbol *> Symbols = Obj->getSymbols(); + OS->Info = InX::SymTab->getSymbolIndex(Symbols[Section->Info]); +} + +template <class ELFT> void OutputSection::finalize() { + InputSection *First = nullptr; + for (BaseCommand *Base : SectionCommands) { + if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) { + if (ISD->Sections.empty()) + continue; + if (First == nullptr) + First = ISD->Sections.front(); + } + if (isa<ByteCommand>(Base) && Type == SHT_NOBITS) + Type = SHT_PROGBITS; + } + + if (Flags & SHF_LINK_ORDER) { + // We must preserve the link order dependency of sections with the + // SHF_LINK_ORDER flag. The dependency is indicated by the sh_link field. We + // need to translate the InputSection sh_link to the OutputSection sh_link, + // all InputSections in the OutputSection have the same dependency. + if (auto *D = First->getLinkOrderDep()) + Link = D->getParent()->SectionIndex; + } + + if (Type == SHT_GROUP) { + finalizeShtGroup<ELFT>(this, First); + return; } - Sec->addSection(cast<InputSection>(IS)); + if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL)) + return; + + if (isa<SyntheticSection>(First)) + return; + + Link = InX::SymTab->getParent()->SectionIndex; + // sh_info for SHT_REL[A] sections should contain the section header index of + // the section to which the relocation applies. + InputSectionBase *S = First->getRelocatedSection(); + Info = S->getOutputSection()->SectionIndex; + Flags |= SHF_INFO_LINK; +} + +// Returns true if S matches /Filename.?\.o$/. +static bool isCrtBeginEnd(StringRef S, StringRef Filename) { + if (!S.endswith(".o")) + return false; + S = S.drop_back(2); + if (S.endswith(Filename)) + return true; + return !S.empty() && S.drop_back().endswith(Filename); } -OutputSectionFactory::~OutputSectionFactory() {} +static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); } +static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); } -SectionKey DenseMapInfo<SectionKey>::getEmptyKey() { - return SectionKey{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0}; +// .ctors and .dtors are sorted by this priority from highest to lowest. +// +// 1. The section was contained in crtbegin (crtbegin contains +// some sentinel value in its .ctors and .dtors so that the runtime +// can find the beginning of the sections.) +// +// 2. The section has an optional priority value in the form of ".ctors.N" +// or ".dtors.N" where N is a number. Unlike .{init,fini}_array, +// they are compared as string rather than number. +// +// 3. The section is just ".ctors" or ".dtors". +// +// 4. The section was contained in crtend, which contains an end marker. +// +// In an ideal world, we don't need this function because .init_array and +// .ctors are duplicate features (and .init_array is newer.) However, there +// are too many real-world use cases of .ctors, so we had no choice to +// support that with this rather ad-hoc semantics. +static bool compCtors(const InputSection *A, const InputSection *B) { + bool BeginA = isCrtbegin(A->File->getName()); + bool BeginB = isCrtbegin(B->File->getName()); + if (BeginA != BeginB) + return BeginA; + bool EndA = isCrtend(A->File->getName()); + bool EndB = isCrtend(B->File->getName()); + if (EndA != EndB) + return EndB; + StringRef X = A->Name; + StringRef Y = B->Name; + assert(X.startswith(".ctors") || X.startswith(".dtors")); + assert(Y.startswith(".ctors") || Y.startswith(".dtors")); + X = X.substr(6); + Y = Y.substr(6); + if (X.empty() && Y.empty()) + return false; + return X < Y; } -SectionKey DenseMapInfo<SectionKey>::getTombstoneKey() { - return SectionKey{DenseMapInfo<StringRef>::getTombstoneKey(), 0, 0}; +// Sorts input sections by the special rules for .ctors and .dtors. +// Unfortunately, the rules are different from the one for .{init,fini}_array. +// Read the comment above. +void OutputSection::sortCtorsDtors() { + assert(SectionCommands.size() == 1); + auto *ISD = cast<InputSectionDescription>(SectionCommands[0]); + std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors); } -unsigned DenseMapInfo<SectionKey>::getHashValue(const SectionKey &Val) { - return hash_combine(Val.Name, Val.Flags, Val.Alignment); +// If an input string is in the form of "foo.N" where N is a number, +// return N. Otherwise, returns 65536, which is one greater than the +// lowest priority. +int elf::getPriority(StringRef S) { + size_t Pos = S.rfind('.'); + if (Pos == StringRef::npos) + return 65536; + int V; + if (!to_integer(S.substr(Pos + 1), V, 10)) + return 65536; + return V; } -bool DenseMapInfo<SectionKey>::isEqual(const SectionKey &LHS, - const SectionKey &RHS) { - return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) && - LHS.Flags == RHS.Flags && LHS.Alignment == RHS.Alignment; +// Sorts input sections by section name suffixes, so that .foo.N comes +// before .foo.M if N < M. Used to sort .{init,fini}_array.N sections. +// We want to keep the original order if the priorities are the same +// because the compiler keeps the original initialization order in a +// translation unit and we need to respect that. +// For more detail, read the section of the GCC's manual about init_priority. +void OutputSection::sortInitFini() { + // Sort sections by priority. + sort([](InputSectionBase *S) { return getPriority(S->Name); }); } -uint64_t elf::getHeaderSize() { - if (Config->OFormatBinary) - return 0; - return Out::ElfHeader->Size + Out::ProgramHeaders->Size; +uint32_t OutputSection::getFiller() { + if (Filler) + return *Filler; + if (Flags & SHF_EXECINSTR) + return Target->TrapInstr; + return 0; } template void OutputSection::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr); template void OutputSection::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr); template void OutputSection::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr); template void OutputSection::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr); + +template void OutputSection::writeTo<ELF32LE>(uint8_t *Buf); +template void OutputSection::writeTo<ELF32BE>(uint8_t *Buf); +template void OutputSection::writeTo<ELF64LE>(uint8_t *Buf); +template void OutputSection::writeTo<ELF64BE>(uint8_t *Buf); + +template void OutputSection::maybeCompress<ELF32LE>(); +template void OutputSection::maybeCompress<ELF32BE>(); +template void OutputSection::maybeCompress<ELF64LE>(); +template void OutputSection::maybeCompress<ELF64BE>(); + +template void OutputSection::finalize<ELF32LE>(); +template void OutputSection::finalize<ELF32BE>(); +template void OutputSection::finalize<ELF64LE>(); +template void OutputSection::finalize<ELF64BE>(); diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index 68b46ebf6a7b..b2845773e9af 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -12,9 +12,10 @@ #include "Config.h" #include "InputSection.h" +#include "LinkerScript.h" #include "Relocations.h" -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELF.h" @@ -22,23 +23,23 @@ namespace lld { namespace elf { struct PhdrEntry; -class SymbolBody; +class Symbol; struct EhSectionPiece; class EhInputSection; class InputSection; class InputSectionBase; class MergeInputSection; class OutputSection; -template <class ELFT> class ObjectFile; +template <class ELFT> class ObjFile; template <class ELFT> class SharedFile; class SharedSymbol; -class DefinedRegular; +class Defined; // This represents a section in an output file. // It is composed of multiple InputSections. // The writer creates multiple OutputSections and assign them unique, // non-overlapping file offsets and VAs. -class OutputSection final : public SectionBase { +class OutputSection final : public BaseCommand, public SectionBase { public: OutputSection(StringRef Name, uint32_t Type, uint64_t Flags); @@ -46,6 +47,8 @@ public: return S->kind() == SectionBase::Output; } + static bool classof(const BaseCommand *C); + uint64_t getLMA() const { return Addr + LMAOffset; } template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *SHdr); @@ -54,42 +57,68 @@ public: uint32_t getPhdrFlags() const; - void updateAlignment(uint32_t Val) { - if (Val > Alignment) - Alignment = Val; - } - - // Pointer to the first section in PT_LOAD segment, which this section - // also resides in. This field is used to correctly compute file offset - // of a section. When two sections share the same load segment, difference - // between their file offsets should be equal to difference between their - // virtual addresses. To compute some section offset we use the following - // formula: Off = Off_first + VA - VA_first. - OutputSection *FirstInPtLoad = nullptr; + // Pointer to the PT_LOAD segment, which this section resides in. This field + // is used to correctly compute file offset of a section. When two sections + // share the same load segment, difference between their file offsets should + // be equal to difference between their virtual addresses. To compute some + // section offset we use the following formula: Off = Off_first + VA - + // VA_first, where Off_first and VA_first is file offset and VA of first + // section in PT_LOAD. + PhdrEntry *PtLoad = nullptr; // Pointer to a relocation section for this section. Usually nullptr because // we consume relocations, but if --emit-relocs is specified (which is rare), // it may have a non-null value. OutputSection *RelocationSection = nullptr; - // The following fields correspond to Elf_Shdr members. + // Initially this field is the number of InputSections that have been added to + // the OutputSection so far. Later on, after a call to assignAddresses, it + // corresponds to the Elf_Shdr member. uint64_t Size = 0; + + // The following fields correspond to Elf_Shdr members. uint64_t Offset = 0; uint64_t LMAOffset = 0; uint64_t Addr = 0; uint32_t ShName = 0; - void addSection(InputSection *S); - std::vector<InputSection *> Sections; + void addSection(InputSection *IS); + // Location in the output buffer. + uint8_t *Loc = nullptr; + + // The following members are normally only used in linker scripts. + MemoryRegion *MemRegion = nullptr; + Expr AddrExpr; + Expr AlignExpr; + Expr LMAExpr; + Expr SubalignExpr; + std::vector<BaseCommand *> SectionCommands; + std::vector<StringRef> Phdrs; + llvm::Optional<uint32_t> Filler; + ConstraintKind Constraint = ConstraintKind::NoConstraint; + std::string Location; + std::string MemoryRegionName; + bool Noload = false; + + template <class ELFT> void finalize(); + template <class ELFT> void writeTo(uint8_t *Buf); + template <class ELFT> void maybeCompress(); + + void sort(std::function<int(InputSectionBase *S)> Order); + void sortInitFini(); + void sortCtorsDtors(); + +private: // Used for implementation of --compress-debug-sections option. std::vector<uint8_t> ZDebugHeader; llvm::SmallVector<char, 1> CompressedData; - // Location in the output buffer. - uint8_t *Loc = nullptr; + uint32_t getFiller(); }; +int getPriority(StringRef S); + // All output sections that are handled by the linker specially are // globally accessible. Writer initializes them, so don't use them // until Writer is initialized. @@ -106,47 +135,17 @@ struct Out { static OutputSection *FiniArray; }; -struct SectionKey { - StringRef Name; - uint64_t Flags; - uint32_t Alignment; -}; } // namespace elf } // namespace lld -namespace llvm { -template <> struct DenseMapInfo<lld::elf::SectionKey> { - static lld::elf::SectionKey getEmptyKey(); - static lld::elf::SectionKey getTombstoneKey(); - static unsigned getHashValue(const lld::elf::SectionKey &Val); - static bool isEqual(const lld::elf::SectionKey &LHS, - const lld::elf::SectionKey &RHS); -}; -} // namespace llvm + namespace lld { namespace elf { -// This class knows how to create an output section for a given -// input section. Output section type is determined by various -// factors, including input section's sh_flags, sh_type and -// linker scripts. -class OutputSectionFactory { -public: - OutputSectionFactory(); - ~OutputSectionFactory(); - - void addInputSec(InputSectionBase *IS, StringRef OutsecName); - void addInputSec(InputSectionBase *IS, StringRef OutsecName, - OutputSection *&Sec); - -private: - llvm::SmallDenseMap<SectionKey, OutputSection *> Map; -}; - uint64_t getHeaderSize(); -void reportDiscarded(InputSectionBase *IS); +void sortByOrder(llvm::MutableArrayRef<InputSection *> In, + std::function<int(InputSectionBase *S)> Order); extern std::vector<OutputSection *> OutputSections; -extern std::vector<OutputSectionCommand *> OutputSectionCommands; } // namespace elf } // namespace lld diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index e5fcb2dcc582..96e409578f5c 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -44,13 +44,14 @@ #include "Relocations.h" #include "Config.h" #include "LinkerScript.h" -#include "Memory.h" #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" +#include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/Memory.h" #include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" @@ -70,30 +71,35 @@ using namespace lld::elf; // >>> referenced by bar.c:12 (/home/alice/src/bar.c:12) // >>> /home/alice/src/bar.o:(.text+0x1) template <class ELFT> -static std::string getLocation(InputSectionBase &S, const SymbolBody &Sym, +static std::string getLocation(InputSectionBase &S, const Symbol &Sym, uint64_t Off) { std::string Msg = "\n>>> defined in " + toString(Sym.File) + "\n>>> referenced by "; - std::string Src = S.getSrcMsg<ELFT>(Off); + std::string Src = S.getSrcMsg<ELFT>(Sym, Off); if (!Src.empty()) Msg += Src + "\n>>> "; - return Msg + S.getObjMsg<ELFT>(Off); + return Msg + S.getObjMsg(Off); } -static bool isPreemptible(const SymbolBody &Body, uint32_t Type) { - // In case of MIPS GP-relative relocations always resolve to a definition - // in a regular input file, ignoring the one-definition rule. So we, - // for example, should not attempt to create a dynamic relocation even - // if the target symbol is preemptible. There are two two MIPS GP-relative - // relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16 - // can be against a preemptible symbol. - // To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all - // relocation types occupy eight bit. In case of N64 ABI we extract first - // relocation from 3-in-1 packet because only the first relocation can - // be against a real symbol. - if (Config->EMachine == EM_MIPS && (Type & 0xff) == R_MIPS_GPREL16) +// This is a MIPS-specific rule. +// +// In case of MIPS GP-relative relocations always resolve to a definition +// in a regular input file, ignoring the one-definition rule. So we, +// for example, should not attempt to create a dynamic relocation even +// if the target symbol is preemptible. There are two two MIPS GP-relative +// relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16 +// can be against a preemptible symbol. +// +// To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all +// relocation types occupy eight bit. In case of N64 ABI we extract first +// relocation from 3-in-1 packet because only the first relocation can +// be against a real symbol. +static bool isMipsGprel(RelType Type) { + if (Config->EMachine != EM_MIPS) return false; - return Body.isPreemptible(); + Type &= 0xff; + return Type == R_MIPS_GPREL16 || Type == R_MICROMIPS_GPREL16 || + Type == R_MICROMIPS_GPREL7_S2; } // This function is similar to the `handleTlsRelocation`. MIPS does not @@ -103,28 +109,28 @@ static bool isPreemptible(const SymbolBody &Body, uint32_t Type) { // Mips has a custom MipsGotSection that handles the writing of GOT entries // without dynamic relocations. template <class ELFT> -static unsigned handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body, +static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, uint64_t Offset, int64_t Addend, RelExpr Expr) { if (Expr == R_MIPS_TLSLD) { if (InX::MipsGot->addTlsIndex() && Config->Pic) - In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::MipsGot, - InX::MipsGot->getTlsIndexOff(), false, - nullptr, 0}); - C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + InX::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::MipsGot, + InX::MipsGot->getTlsIndexOff(), false, nullptr, + 0}); + C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } if (Expr == R_MIPS_TLSGD) { - if (InX::MipsGot->addDynTlsEntry(Body) && Body.isPreemptible()) { - uint64_t Off = InX::MipsGot->getGlobalDynOffset(Body); - In<ELFT>::RelaDyn->addReloc( - {Target->TlsModuleIndexRel, InX::MipsGot, Off, false, &Body, 0}); - if (Body.isPreemptible()) - In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, InX::MipsGot, - Off + Config->Wordsize, false, &Body, 0}); + if (InX::MipsGot->addDynTlsEntry(Sym) && Sym.IsPreemptible) { + uint64_t Off = InX::MipsGot->getGlobalDynOffset(Sym); + InX::RelaDyn->addReloc( + {Target->TlsModuleIndexRel, InX::MipsGot, Off, false, &Sym, 0}); + if (Sym.IsPreemptible) + InX::RelaDyn->addReloc({Target->TlsOffsetRel, InX::MipsGot, + Off + Config->Wordsize, false, &Sym, 0}); } - C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } return 0; @@ -145,19 +151,18 @@ static unsigned handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body, // GOT[e0] Module Index (Used to find pointer to TLS block at run-time) // GOT[e1] Offset of symbol in TLS block template <class ELFT> -static unsigned handleARMTlsRelocation(uint32_t Type, SymbolBody &Body, +static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, uint64_t Offset, int64_t Addend, RelExpr Expr) { // The Dynamic TLS Module Index Relocation for a symbol defined in an - // executable is always 1. If the target Symbol is not preemtible then + // executable is always 1. If the target Symbol is not preemptible then // we know the offset into the TLS block at static link time. - bool NeedDynId = Body.isPreemptible() || Config->Shared; - bool NeedDynOff = Body.isPreemptible(); + bool NeedDynId = Sym.IsPreemptible || Config->Shared; + bool NeedDynOff = Sym.IsPreemptible; - auto AddTlsReloc = [&](uint64_t Off, uint32_t Type, SymbolBody *Dest, - bool Dyn) { + auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) { if (Dyn) - In<ELFT>::RelaDyn->addReloc({Type, InX::Got, Off, false, Dest, 0}); + InX::RelaDyn->addReloc({Type, InX::Got, Off, false, Dest, 0}); else InX::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest}); }; @@ -168,8 +173,8 @@ static unsigned handleARMTlsRelocation(uint32_t Type, SymbolBody &Body, // module. GOT[e1] is unused. There only needs to be one module index entry. if (Expr == R_TLSLD_PC && InX::Got->addTlsIndex()) { AddTlsReloc(InX::Got->getTlsIndexOff(), Target->TlsModuleIndexRel, - NeedDynId ? nullptr : &Body, NeedDynId); - C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + NeedDynId ? nullptr : &Sym, NeedDynId); + C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } @@ -177,13 +182,13 @@ static unsigned handleARMTlsRelocation(uint32_t Type, SymbolBody &Body, // the module index and offset of symbol in TLS block we can fill these in // using static GOT relocations. if (Expr == R_TLSGD_PC) { - if (InX::Got->addDynTlsEntry(Body)) { - uint64_t Off = InX::Got->getGlobalDynOffset(Body); - AddTlsReloc(Off, Target->TlsModuleIndexRel, &Body, NeedDynId); - AddTlsReloc(Off + Config->Wordsize, Target->TlsOffsetRel, &Body, + if (InX::Got->addDynTlsEntry(Sym)) { + uint64_t Off = InX::Got->getGlobalDynOffset(Sym); + AddTlsReloc(Off, Target->TlsModuleIndexRel, &Sym, NeedDynId); + AddTlsReloc(Off + Config->Wordsize, Target->TlsOffsetRel, &Sym, NeedDynOff); } - C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } return 0; @@ -192,29 +197,28 @@ static unsigned handleARMTlsRelocation(uint32_t Type, SymbolBody &Body, // Returns the number of relocations processed. template <class ELFT> static unsigned -handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C, +handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, typename ELFT::uint Offset, int64_t Addend, RelExpr Expr) { if (!(C.Flags & SHF_ALLOC)) return 0; - if (!Body.isTls()) + if (!Sym.isTls()) return 0; if (Config->EMachine == EM_ARM) - return handleARMTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr); + return handleARMTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr); if (Config->EMachine == EM_MIPS) - return handleMipsTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr); + return handleMipsTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr); - bool IsPreemptible = isPreemptible(Body, Type); if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) && Config->Shared) { - if (InX::Got->addDynTlsEntry(Body)) { - uint64_t Off = InX::Got->getGlobalDynOffset(Body); - In<ELFT>::RelaDyn->addReloc( - {Target->TlsDescRel, InX::Got, Off, !IsPreemptible, &Body, 0}); + if (InX::Got->addDynTlsEntry(Sym)) { + uint64_t Off = InX::Got->getGlobalDynOffset(Sym); + InX::RelaDyn->addReloc( + {Target->TlsDescRel, InX::Got, Off, !Sym.IsPreemptible, &Sym, 0}); } if (Expr != R_TLSDESC_CALL) - C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } @@ -222,61 +226,59 @@ handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C, // Local-Dynamic relocs can be relaxed to Local-Exec. if (!Config->Shared) { C.Relocations.push_back( - {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body}); + {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym}); return 2; } if (InX::Got->addTlsIndex()) - In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::Got, - InX::Got->getTlsIndexOff(), false, nullptr, - 0}); - C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + InX::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::Got, + InX::Got->getTlsIndexOff(), false, nullptr, 0}); + C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } // Local-Dynamic relocs can be relaxed to Local-Exec. if (isRelExprOneOf<R_ABS, R_TLSLD, R_TLSLD_PC>(Expr) && !Config->Shared) { - C.Relocations.push_back( - {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body}); + C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym}); return 1; } if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD, R_TLSGD_PC>(Expr)) { if (Config->Shared) { - if (InX::Got->addDynTlsEntry(Body)) { - uint64_t Off = InX::Got->getGlobalDynOffset(Body); - In<ELFT>::RelaDyn->addReloc( - {Target->TlsModuleIndexRel, InX::Got, Off, false, &Body, 0}); + if (InX::Got->addDynTlsEntry(Sym)) { + uint64_t Off = InX::Got->getGlobalDynOffset(Sym); + InX::RelaDyn->addReloc( + {Target->TlsModuleIndexRel, InX::Got, Off, false, &Sym, 0}); // If the symbol is preemptible we need the dynamic linker to write // the offset too. uint64_t OffsetOff = Off + Config->Wordsize; - if (IsPreemptible) - In<ELFT>::RelaDyn->addReloc( - {Target->TlsOffsetRel, InX::Got, OffsetOff, false, &Body, 0}); + if (Sym.IsPreemptible) + InX::RelaDyn->addReloc( + {Target->TlsOffsetRel, InX::Got, OffsetOff, false, &Sym, 0}); else InX::Got->Relocations.push_back( - {R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Body}); + {R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym}); } - C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec // depending on the symbol being locally defined or not. - if (IsPreemptible) { + if (Sym.IsPreemptible) { C.Relocations.push_back( {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type, - Offset, Addend, &Body}); - if (!Body.isInGot()) { - InX::Got->addEntry(Body); - In<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, InX::Got, - Body.getGotOffset(), false, &Body, 0}); + Offset, Addend, &Sym}); + if (!Sym.isInGot()) { + InX::Got->addEntry(Sym); + InX::RelaDyn->addReloc( + {Target->TlsGotRel, InX::Got, Sym.getGotOffset(), false, &Sym, 0}); } } else { C.Relocations.push_back( {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type, - Offset, Addend, &Body}); + Offset, Addend, &Sym}); } return Target->TlsGdRelaxSkip; } @@ -284,9 +286,8 @@ handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C, // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally // defined. if (isRelExprOneOf<R_GOT, R_GOT_FROM_END, R_GOT_PC, R_GOT_PAGE_PC>(Expr) && - !Config->Shared && !IsPreemptible) { - C.Relocations.push_back( - {R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body}); + !Config->Shared && !Sym.IsPreemptible) { + C.Relocations.push_back({R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Sym}); return 1; } @@ -295,12 +296,22 @@ handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C, return 0; } -static uint32_t getMipsPairType(uint32_t Type, const SymbolBody &Sym) { +static RelType getMipsPairType(RelType Type, bool IsLocal) { switch (Type) { case R_MIPS_HI16: return R_MIPS_LO16; case R_MIPS_GOT16: - return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE; + // In case of global symbol, the R_MIPS_GOT16 relocation does not + // have a pair. Each global symbol has a unique entry in the GOT + // and a corresponding instruction with help of the R_MIPS_GOT16 + // relocation loads an address of the symbol. In case of local + // symbol, the R_MIPS_GOT16 relocation creates a GOT entry to hold + // the high 16 bits of the symbol's value. A paired R_MIPS_LO16 + // relocations handle low 16 bits of the address. That allows + // to allocate only one GOT entry for every 64 KBytes of local data. + return IsLocal ? R_MIPS_LO16 : R_MIPS_NONE; + case R_MICROMIPS_GOT16: + return IsLocal ? R_MICROMIPS_LO16 : R_MIPS_NONE; case R_MIPS_PCHI16: return R_MIPS_PCLO16; case R_MICROMIPS_HI16: @@ -312,16 +323,16 @@ static uint32_t getMipsPairType(uint32_t Type, const SymbolBody &Sym) { // True if non-preemptable symbol always has the same value regardless of where // the DSO is loaded. -static bool isAbsolute(const SymbolBody &Body) { - if (Body.isUndefined()) - return !Body.isLocal() && Body.symbol()->isWeak(); - if (const auto *DR = dyn_cast<DefinedRegular>(&Body)) +static bool isAbsolute(const Symbol &Sym) { + if (Sym.isUndefWeak()) + return true; + if (const auto *DR = dyn_cast<Defined>(&Sym)) return DR->Section == nullptr; // Absolute symbol. return false; } -static bool isAbsoluteValue(const SymbolBody &Body) { - return isAbsolute(Body) || Body.isTls(); +static bool isAbsoluteValue(const Symbol &Sym) { + return isAbsolute(Sym) || Sym.isTls(); } // Returns true if Expr refers a PLT entry. @@ -355,8 +366,7 @@ static bool isRelExpr(RelExpr Expr) { // If this function returns false, that means we need to emit a // dynamic relocation so that the relocation will be fixed at load-time. template <class ELFT> -static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type, - const SymbolBody &Body, +static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, InputSectionBase &S, uint64_t RelOff) { // These expressions always compute a constant if (isRelExprOneOf<R_SIZE, R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, @@ -371,14 +381,14 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type, if (E == R_GOT || E == R_PLT || E == R_TLSDESC) return Target->usesOnlyLowPageBits(Type) || !Config->Pic; - if (isPreemptible(Body, Type)) + if (Sym.IsPreemptible) return false; if (!Config->Pic) return true; // For the target and the relocation, we want to know if they are // absolute or relative. - bool AbsVal = isAbsoluteValue(Body); + bool AbsVal = isAbsoluteValue(Sym); bool RelE = isRelExpr(E); if (AbsVal && !RelE) return true; @@ -396,11 +406,11 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type, // between start of a function and '_gp' value and defined as absolute just // to simplify the code. assert(AbsVal && RelE); - if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) + if (Sym.isUndefWeak()) return true; error("relocation " + toString(Type) + " cannot refer to absolute symbol: " + - toString(Body) + getLocation<ELFT>(S, Body, RelOff)); + toString(Sym) + getLocation<ELFT>(S, Sym, RelOff)); return true; } @@ -431,14 +441,13 @@ static RelExpr fromPlt(RelExpr Expr) { // Returns true if a given shared symbol is in a read-only segment in a DSO. template <class ELFT> static bool isReadOnly(SharedSymbol *SS) { typedef typename ELFT::Phdr Elf_Phdr; - uint64_t Value = SS->getValue<ELFT>(); // Determine if the symbol is read-only by scanning the DSO's program headers. - auto *File = cast<SharedFile<ELFT>>(SS->File); + const SharedFile<ELFT> *File = SS->getFile<ELFT>(); for (const Elf_Phdr &Phdr : check(File->getObj().program_headers())) if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) && - !(Phdr.p_flags & ELF::PF_W) && Value >= Phdr.p_vaddr && - Value < Phdr.p_vaddr + Phdr.p_memsz) + !(Phdr.p_flags & ELF::PF_W) && SS->Value >= Phdr.p_vaddr && + SS->Value < Phdr.p_vaddr + Phdr.p_memsz) return true; return false; } @@ -452,16 +461,15 @@ template <class ELFT> static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) { typedef typename ELFT::Sym Elf_Sym; - auto *File = cast<SharedFile<ELFT>>(SS->File); - uint64_t Shndx = SS->getShndx<ELFT>(); - uint64_t Value = SS->getValue<ELFT>(); + SharedFile<ELFT> *File = SS->getFile<ELFT>(); std::vector<SharedSymbol *> Ret; - for (const Elf_Sym &S : File->getGlobalSymbols()) { - if (S.st_shndx != Shndx || S.st_value != Value) + for (const Elf_Sym &S : File->getGlobalELFSyms()) { + if (S.st_shndx == SHN_UNDEF || S.st_shndx == SHN_ABS || + S.st_value != SS->Value) continue; StringRef Name = check(S.getName(File->getStringTable())); - SymbolBody *Sym = Symtab<ELFT>::X->find(Name); + Symbol *Sym = Symtab->find(Name); if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym)) Ret.push_back(Alias); } @@ -512,79 +520,101 @@ static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) { // define an accessor getV(). template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) { // Copy relocation against zero-sized symbol doesn't make sense. - uint64_t SymSize = SS->template getSize<ELFT>(); + uint64_t SymSize = SS->getSize(); if (SymSize == 0) fatal("cannot create a copy relocation for symbol " + toString(*SS)); // See if this symbol is in a read-only segment. If so, preserve the symbol's // memory protection by reserving space in the .bss.rel.ro section. bool IsReadOnly = isReadOnly<ELFT>(SS); - BssSection *Sec = IsReadOnly ? InX::BssRelRo : InX::Bss; - uint64_t Off = Sec->reserveSpace(SymSize, SS->getAlignment<ELFT>()); + BssSection *Sec = make<BssSection>(IsReadOnly ? ".bss.rel.ro" : ".bss", + SymSize, SS->Alignment); + if (IsReadOnly) + InX::BssRelRo->getParent()->addSection(Sec); + else + InX::Bss->getParent()->addSection(Sec); // Look through the DSO's dynamic symbol table for aliases and create a // dynamic symbol for each one. This causes the copy relocation to correctly // interpose any aliases. for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) { - Sym->NeedsCopy = true; Sym->CopyRelSec = Sec; - Sym->CopyRelSecOff = Off; - Sym->symbol()->IsUsedInRegularObj = true; + Sym->IsPreemptible = false; + Sym->IsUsedInRegularObj = true; + Sym->Used = true; } - In<ELFT>::RelaDyn->addReloc({Target->CopyRel, Sec, Off, false, SS, 0}); + InX::RelaDyn->addReloc({Target->CopyRel, Sec, 0, false, SS, 0}); +} + +static void errorOrWarn(const Twine &Msg) { + if (!Config->NoinhibitExec) + error(Msg); + else + warn(Msg); } template <class ELFT> -static RelExpr adjustExpr(SymbolBody &Body, RelExpr Expr, uint32_t Type, - const uint8_t *Data, InputSectionBase &S, - typename ELFT::uint RelOff) { - if (Body.isGnuIFunc()) { - Expr = toPlt(Expr); - } else if (!isPreemptible(Body, Type)) { - if (needsPlt(Expr)) - Expr = fromPlt(Expr); - if (Expr == R_GOT_PC && !isAbsoluteValue(Body)) - Expr = Target->adjustRelaxExpr(Type, Data, Expr); - } +static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, + InputSectionBase &S, uint64_t RelOff) { + // We can create any dynamic relocation if a section is simply writable. + if (S.Flags & SHF_WRITE) + return Expr; - bool IsWrite = !Config->ZText || (S.Flags & SHF_WRITE); - if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, S, RelOff)) + // Or, if we are allowed to create dynamic relocations against + // read-only sections (i.e. unless "-z notext" is given), + // we can create a dynamic relocation as we want, too. + if (!Config->ZText) return Expr; - // This relocation would require the dynamic linker to write a value to read - // only memory. We can hack around it if we are producing an executable and + // If a relocation can be applied at link-time, we don't need to + // create a dynamic relocation in the first place. + if (isStaticLinkTimeConstant<ELFT>(Expr, Type, Sym, S, RelOff)) + return Expr; + + // If we got here we know that this relocation would require the dynamic + // linker to write a value to read only memory. + + // If the relocation is to a weak undef, give up on it and produce a + // non preemptible 0. + if (Sym.isUndefWeak()) { + Sym.IsPreemptible = false; + return Expr; + } + + // We can hack around it if we are producing an executable and // the refered symbol can be preemepted to refer to the executable. if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) { - error("can't create dynamic relocation " + toString(Type) + " against " + - (Body.getName().empty() ? "local symbol" - : "symbol: " + toString(Body)) + - " in readonly segment" + getLocation<ELFT>(S, Body, RelOff)); + error( + "can't create dynamic relocation " + toString(Type) + " against " + + (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) + + " in readonly segment; recompile object files with -fPIC" + + getLocation<ELFT>(S, Sym, RelOff)); return Expr; } - if (Body.getVisibility() != STV_DEFAULT) { - error("cannot preempt symbol: " + toString(Body) + - getLocation<ELFT>(S, Body, RelOff)); + if (Sym.getVisibility() != STV_DEFAULT) { + error("cannot preempt symbol: " + toString(Sym) + + getLocation<ELFT>(S, Sym, RelOff)); return Expr; } - if (Body.isObject()) { + if (Sym.isObject()) { // Produce a copy relocation. - auto *B = cast<SharedSymbol>(&Body); - if (!B->NeedsCopy) { + auto *B = dyn_cast<SharedSymbol>(&Sym); + if (B && !B->CopyRelSec) { if (Config->ZNocopyreloc) error("unresolvable relocation " + toString(Type) + " against symbol '" + toString(*B) + "'; recompile with -fPIC or remove '-z nocopyreloc'" + - getLocation<ELFT>(S, Body, RelOff)); + getLocation<ELFT>(S, Sym, RelOff)); addCopyRelSymbol<ELFT>(B); } return Expr; } - if (Body.isFunc()) { + if (Sym.isFunc()) { // This handles a non PIC program call to function in a shared library. In // an ideal world, we could just report an error saying the relocation can // overflow at runtime. In the real world with glibc, crt1.o has a @@ -605,39 +635,25 @@ static RelExpr adjustExpr(SymbolBody &Body, RelExpr Expr, uint32_t Type, // that points to the real function is a dedicated got entry used by the // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, // R_386_JMP_SLOT, etc). - Body.NeedsPltAddr = true; + Sym.NeedsPltAddr = true; + Sym.IsPreemptible = false; return toPlt(Expr); } - error("symbol '" + toString(Body) + "' defined in " + toString(Body.File) + - " has no type"); + errorOrWarn("symbol '" + toString(Sym) + "' defined in " + + toString(Sym.File) + " has no type"); return Expr; } -// Returns an addend of a given relocation. If it is RELA, an addend -// is in a relocation itself. If it is REL, we need to read it from an -// input section. -template <class ELFT, class RelTy> -static int64_t computeAddend(const RelTy &Rel, const uint8_t *Buf) { - uint32_t Type = Rel.getType(Config->IsMips64EL); - int64_t A = RelTy::IsRela - ? getAddend<ELFT>(Rel) - : Target->getImplicitAddend(Buf + Rel.r_offset, Type); - - if (Config->EMachine == EM_PPC64 && Config->Pic && Type == R_PPC64_TOC) - A += getPPC64TocBase(); - return A; -} - // MIPS has an odd notion of "paired" relocations to calculate addends. // For example, if a relocation is of R_MIPS_HI16, there must be a // R_MIPS_LO16 relocation after that, and an addend is calculated using // the two relocations. template <class ELFT, class RelTy> -static int64_t computeMipsAddend(const RelTy &Rel, InputSectionBase &Sec, - RelExpr Expr, SymbolBody &Body, - const RelTy *End) { - if (Expr == R_MIPS_GOTREL && Body.isLocal()) +static int64_t computeMipsAddend(const RelTy &Rel, const RelTy *End, + InputSectionBase &Sec, RelExpr Expr, + bool IsLocal) { + if (Expr == R_MIPS_GOTREL && IsLocal) return Sec.getFile<ELFT>()->MipsGp0; // The ABI says that the paired relocation is used only for REL. @@ -645,8 +661,8 @@ static int64_t computeMipsAddend(const RelTy &Rel, InputSectionBase &Sec, if (RelTy::IsRela) return 0; - uint32_t Type = Rel.getType(Config->IsMips64EL); - uint32_t PairTy = getMipsPairType(Type, Body); + RelType Type = Rel.getType(Config->IsMips64EL); + uint32_t PairTy = getMipsPairType(Type, IsLocal); if (PairTy == R_MIPS_NONE) return 0; @@ -655,64 +671,88 @@ static int64_t computeMipsAddend(const RelTy &Rel, InputSectionBase &Sec, // To make things worse, paired relocations might not be contiguous in // the relocation table, so we need to do linear search. *sigh* - for (const RelTy *RI = &Rel; RI != End; ++RI) { - if (RI->getType(Config->IsMips64EL) != PairTy) - continue; - if (RI->getSymbol(Config->IsMips64EL) != SymIndex) - continue; - - endianness E = Config->Endianness; - int32_t Hi = (read32(Buf + Rel.r_offset, E) & 0xffff) << 16; - int32_t Lo = SignExtend32<16>(read32(Buf + RI->r_offset, E)); - return Hi + Lo; - } + for (const RelTy *RI = &Rel; RI != End; ++RI) + if (RI->getType(Config->IsMips64EL) == PairTy && + RI->getSymbol(Config->IsMips64EL) == SymIndex) + return Target->getImplicitAddend(Buf + RI->r_offset, PairTy); warn("can't find matching " + toString(PairTy) + " relocation for " + toString(Type)); return 0; } +// Returns an addend of a given relocation. If it is RELA, an addend +// is in a relocation itself. If it is REL, we need to read it from an +// input section. +template <class ELFT, class RelTy> +static int64_t computeAddend(const RelTy &Rel, const RelTy *End, + InputSectionBase &Sec, RelExpr Expr, + bool IsLocal) { + int64_t Addend; + RelType Type = Rel.getType(Config->IsMips64EL); + + if (RelTy::IsRela) { + Addend = getAddend<ELFT>(Rel); + } else { + const uint8_t *Buf = Sec.Data.data(); + Addend = Target->getImplicitAddend(Buf + Rel.r_offset, Type); + } + + if (Config->EMachine == EM_PPC64 && Config->Pic && Type == R_PPC64_TOC) + Addend += getPPC64TocBase(); + if (Config->EMachine == EM_MIPS) + Addend += computeMipsAddend<ELFT>(Rel, End, Sec, Expr, IsLocal); + + return Addend; +} + +// Report an undefined symbol if necessary. +// Returns true if this function printed out an error message. template <class ELFT> -static void reportUndefined(SymbolBody &Sym, InputSectionBase &S, - uint64_t Offset) { +static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, + uint64_t Offset) { if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll) - return; + return false; + + if (Sym.isLocal() || !Sym.isUndefined() || Sym.isWeak()) + return false; - bool CanBeExternal = Sym.symbol()->computeBinding() != STB_LOCAL && - Sym.getVisibility() == STV_DEFAULT; + bool CanBeExternal = + Sym.computeBinding() != STB_LOCAL && Sym.getVisibility() == STV_DEFAULT; if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal) - return; + return false; std::string Msg = "undefined symbol: " + toString(Sym) + "\n>>> referenced by "; - std::string Src = S.getSrcMsg<ELFT>(Offset); + std::string Src = Sec.getSrcMsg<ELFT>(Sym, Offset); if (!Src.empty()) Msg += Src + "\n>>> "; - Msg += S.getObjMsg<ELFT>(Offset); + Msg += Sec.getObjMsg(Offset); - if (Config->UnresolvedSymbols == UnresolvedPolicy::WarnAll || - (Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal)) { + if ((Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal) || + Config->NoinhibitExec) { warn(Msg); - } else { - error(Msg); + return false; } + + error(Msg); + return true; } -template <class RelTy> -static std::pair<uint32_t, uint32_t> -mergeMipsN32RelTypes(uint32_t Type, uint32_t Offset, RelTy *I, RelTy *E) { - // MIPS N32 ABI treats series of successive relocations with the same offset - // as a single relocation. The similar approach used by N64 ABI, but this ABI - // packs all relocations into the single relocation record. Here we emulate - // this for the N32 ABI. Iterate over relocation with the same offset and put - // theirs types into the single bit-set. - uint32_t Processed = 0; - for (; I != E && Offset == I->r_offset; ++I) { - ++Processed; - Type |= I->getType(Config->IsMips64EL) << (8 * Processed); - } - return std::make_pair(Type, Processed); +// MIPS N32 ABI treats series of successive relocations with the same offset +// as a single relocation. The similar approach used by N64 ABI, but this ABI +// packs all relocations into the single relocation record. Here we emulate +// this for the N32 ABI. Iterate over relocation with the same offset and put +// theirs types into the single bit-set. +template <class RelTy> static RelType getMipsN32RelType(RelTy *&Rel, RelTy *End) { + RelType Type = Rel->getType(Config->IsMips64EL); + uint64_t Offset = Rel->r_offset; + + int N = 0; + while (Rel + 1 != End && (Rel + 1)->r_offset == Offset) + Type |= (++Rel)->getType(Config->IsMips64EL) << (8 * ++N); + return Type; } // .eh_frame sections are mergeable input sections, so their input @@ -730,73 +770,84 @@ namespace { class OffsetGetter { public: explicit OffsetGetter(InputSectionBase &Sec) { - if (auto *Eh = dyn_cast<EhInputSection>(&Sec)) { - P = Eh->Pieces; - Size = Eh->Pieces.size(); - } + if (auto *Eh = dyn_cast<EhInputSection>(&Sec)) + Pieces = Eh->Pieces; } // Translates offsets in input sections to offsets in output sections. - // Given offset must increase monotonically. We assume that P is + // Given offset must increase monotonically. We assume that Piece is // sorted by InputOff. uint64_t get(uint64_t Off) { - if (P.empty()) + if (Pieces.empty()) return Off; - while (I != Size && P[I].InputOff + P[I].size() <= Off) + while (I != Pieces.size() && Pieces[I].InputOff + Pieces[I].Size <= Off) ++I; - if (I == Size) + if (I == Pieces.size()) return Off; - // P must be contiguous, so there must be no holes in between. - assert(P[I].InputOff <= Off && "Relocation not in any piece"); + // Pieces must be contiguous, so there must be no holes in between. + assert(Pieces[I].InputOff <= Off && "Relocation not in any piece"); // Offset -1 means that the piece is dead (i.e. garbage collected). - if (P[I].OutputOff == -1) + if (Pieces[I].OutputOff == -1) return -1; - return P[I].OutputOff + Off - P[I].InputOff; + return Pieces[I].OutputOff + Off - Pieces[I].InputOff; } private: - ArrayRef<EhSectionPiece> P; + ArrayRef<EhSectionPiece> Pieces; size_t I = 0; - size_t Size; }; } // namespace template <class ELFT, class GotPltSection> static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt, - RelocationSection<ELFT> *Rel, uint32_t Type, - SymbolBody &Sym, bool UseSymVA) { + RelocationBaseSection *Rel, RelType Type, Symbol &Sym, + bool UseSymVA) { Plt->addEntry<ELFT>(Sym); GotPlt->addEntry(Sym); Rel->addReloc({Type, GotPlt, Sym.getGotPltOffset(), UseSymVA, &Sym, 0}); } -template <class ELFT> -static void addGotEntry(SymbolBody &Sym, bool Preemptible) { +template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) { InX::Got->addEntry(Sym); + RelExpr Expr = Sym.isTls() ? R_TLS : R_ABS; uint64_t Off = Sym.getGotOffset(); - uint32_t DynType; - RelExpr Expr = R_ABS; - - if (Sym.isTls()) { - DynType = Target->TlsGotRel; - Expr = R_TLS; - } else if (!Preemptible && Config->Pic && !isAbsolute(Sym)) { - DynType = Target->RelativeRel; - } else { - DynType = Target->GotRel; - } - bool Constant = !Preemptible && !(Config->Pic && !isAbsolute(Sym)); - if (!Constant) - In<ELFT>::RelaDyn->addReloc( - {DynType, InX::Got, Off, !Preemptible, &Sym, 0}); + // If a GOT slot value can be calculated at link-time, which is now, + // we can just fill that out. + // + // (We don't actually write a value to a GOT slot right now, but we + // add a static relocation to a Relocations vector so that + // InputSection::relocate will do the work for us. We may be able + // to just write a value now, but it is a TODO.) + bool IsLinkTimeConstant = !Preemptible && (!Config->Pic || isAbsolute(Sym)); + if (IsLinkTimeConstant) { + InX::Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym}); + return; + } - if (Constant || (!Config->IsRela && !Preemptible)) - InX::Got->Relocations.push_back({Expr, DynType, Off, 0, &Sym}); + // Otherwise, we emit a dynamic relocation to .rel[a].dyn so that + // the GOT slot will be fixed at load-time. + RelType Type; + if (Sym.isTls()) + Type = Target->TlsGotRel; + else if (!Preemptible && Config->Pic && !isAbsolute(Sym)) + Type = Target->RelativeRel; + else + Type = Target->GotRel; + InX::RelaDyn->addReloc({Type, InX::Got, Off, !Preemptible, &Sym, 0}); + + // REL type relocations don't have addend fields unlike RELAs, and + // their addends are stored to the section to which they are applied. + // So, store addends if we need to. + // + // This is ugly -- the difference between REL and RELA should be + // handled in a better way. It's a TODO. + if (!Config->IsRela) + InX::Got->Relocations.push_back({R_ABS, Target->GotRel, Off, 0, &Sym}); } // The reason we have to do this early scan is as follows @@ -816,41 +867,64 @@ template <class ELFT, class RelTy> static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { OffsetGetter GetOffset(Sec); + // Not all relocations end up in Sec.Relocations, but a lot do. + Sec.Relocations.reserve(Rels.size()); + for (auto I = Rels.begin(), End = Rels.end(); I != End; ++I) { const RelTy &Rel = *I; - SymbolBody &Body = Sec.getFile<ELFT>()->getRelocTargetSym(Rel); - uint32_t Type = Rel.getType(Config->IsMips64EL); - - if (Config->MipsN32Abi) { - uint32_t Processed; - std::tie(Type, Processed) = - mergeMipsN32RelTypes(Type, Rel.r_offset, I + 1, End); - I += Processed; - } + Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel); + RelType Type = Rel.getType(Config->IsMips64EL); + + // Deal with MIPS oddity. + if (Config->MipsN32Abi) + Type = getMipsN32RelType(I, End); - // Compute the offset of this section in the output section. + // Get an offset in an output section this relocation is applied to. uint64_t Offset = GetOffset.get(Rel.r_offset); if (Offset == uint64_t(-1)) continue; - // Report undefined symbols. The fact that we report undefined - // symbols here means that we report undefined symbols only when - // they have relocations pointing to them. We don't care about - // undefined symbols that are in dead-stripped sections. - if (!Body.isLocal() && Body.isUndefined() && !Body.symbol()->isWeak()) - reportUndefined<ELFT>(Body, Sec, Rel.r_offset); + // Skip if the target symbol is an erroneous undefined symbol. + if (maybeReportUndefined<ELFT>(Sym, Sec, Rel.r_offset)) + continue; RelExpr Expr = - Target->getRelExpr(Type, Body, Sec.Data.begin() + Rel.r_offset); + Target->getRelExpr(Type, Sym, Sec.Data.begin() + Rel.r_offset); // Ignore "hint" relocations because they are only markers for relaxation. if (isRelExprOneOf<R_HINT, R_NONE>(Expr)) continue; - bool Preemptible = isPreemptible(Body, Type); - Expr = adjustExpr<ELFT>(Body, Expr, Type, Sec.Data.data() + Rel.r_offset, - Sec, Rel.r_offset); - if (ErrorCount) + // Handle yet another MIPS-ness. + if (isMipsGprel(Type)) { + int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal()); + Sec.Relocations.push_back({R_MIPS_GOTREL, Type, Offset, Addend, &Sym}); + continue; + } + + bool Preemptible = Sym.IsPreemptible; + + // Strenghten or relax a PLT access. + // + // GNU ifunc symbols must be accessed via PLT because their addresses + // are determined by runtime. + // + // On the other hand, if we know that a PLT entry will be resolved within + // the same ELF module, we can skip PLT access and directly jump to the + // destination function. For example, if we are linking a main exectuable, + // all dynamic symbols that can be resolved within the executable will + // actually be resolved that way at runtime, because the main exectuable + // is always at the beginning of a search list. We can leverage that fact. + if (Sym.isGnuIFunc()) + Expr = toPlt(Expr); + else if (!Preemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) + Expr = + Target->adjustRelaxExpr(Type, Sec.Data.data() + Rel.r_offset, Expr); + else if (!Preemptible) + Expr = fromPlt(Expr); + + Expr = adjustExpr<ELFT>(Sym, Expr, Type, Sec, Rel.r_offset); + if (errorCount()) continue; // This relocation does not require got entry, but it is relative to got and @@ -860,26 +934,24 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { InX::Got->HasGotOffRel = true; // Read an addend. - int64_t Addend = computeAddend<ELFT>(Rel, Sec.Data.data()); - if (Config->EMachine == EM_MIPS) - Addend += computeMipsAddend<ELFT>(Rel, Sec, Expr, Body, End); + int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal()); // Process some TLS relocations, including relaxing TLS relocations. // Note that this function does not handle all TLS relocations. if (unsigned Processed = - handleTlsRelocation<ELFT>(Type, Body, Sec, Offset, Addend, Expr)) { + handleTlsRelocation<ELFT>(Type, Sym, Sec, Offset, Addend, Expr)) { I += (Processed - 1); continue; } // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. - if (needsPlt(Expr) && !Body.isInPlt()) { - if (Body.isGnuIFunc() && !Preemptible) - addPltEntry(InX::Iplt, InX::IgotPlt, In<ELFT>::RelaIplt, - Target->IRelativeRel, Body, true); + if (needsPlt(Expr) && !Sym.isInPlt()) { + if (Sym.isGnuIFunc() && !Preemptible) + addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt, + Target->IRelativeRel, Sym, true); else - addPltEntry(InX::Plt, InX::GotPlt, In<ELFT>::RelaPlt, Target->PltRel, - Body, !Preemptible); + addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel, + Sym, !Preemptible); } // Create a GOT slot if a relocation needs GOT. @@ -892,25 +964,26 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { // See "Global Offset Table" in Chapter 5 in the following document // for detailed description: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - InX::MipsGot->addEntry(Body, Addend, Expr); - if (Body.isTls() && Body.isPreemptible()) - In<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, InX::MipsGot, - Body.getGotOffset(), false, &Body, 0}); - } else if (!Body.isInGot()) { - addGotEntry<ELFT>(Body, Preemptible); + InX::MipsGot->addEntry(Sym, Addend, Expr); + if (Sym.isTls() && Sym.IsPreemptible) + InX::RelaDyn->addReloc({Target->TlsGotRel, InX::MipsGot, + Sym.getGotOffset(), false, &Sym, 0}); + } else if (!Sym.isInGot()) { + addGotEntry<ELFT>(Sym, Preemptible); } } - if (!needsPlt(Expr) && !needsGot(Expr) && isPreemptible(Body, Type)) { + if (!needsPlt(Expr) && !needsGot(Expr) && Sym.IsPreemptible) { // We don't know anything about the finaly symbol. Just ask the dynamic // linker to handle the relocation for us. if (!Target->isPicRel(Type)) - error("relocation " + toString(Type) + - " cannot be used against shared object; recompile with -fPIC" + - getLocation<ELFT>(Sec, Body, Offset)); + errorOrWarn( + "relocation " + toString(Type) + + " cannot be used against shared object; recompile with -fPIC" + + getLocation<ELFT>(Sec, Sym, Offset)); - In<ELFT>::RelaDyn->addReloc( - {Target->getDynRel(Type), &Sec, Offset, false, &Body, Addend}); + InX::RelaDyn->addReloc( + {Target->getDynRel(Type), &Sec, Offset, false, &Sym, Addend}); // MIPS ABI turns using of GOT and dynamic relocations inside out. // While regular ABI uses dynamic relocations to fill up GOT entries @@ -928,32 +1001,40 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { // a dynamic relocation. // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19 if (Config->EMachine == EM_MIPS) - InX::MipsGot->addEntry(Body, Addend, Expr); + InX::MipsGot->addEntry(Sym, Addend, Expr); continue; } // If the relocation points to something in the file, we can process it. bool IsConstant = - isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, Sec, Rel.r_offset); + isStaticLinkTimeConstant<ELFT>(Expr, Type, Sym, Sec, Rel.r_offset); // The size is not going to change, so we fold it in here. if (Expr == R_SIZE) - Addend += Body.getSize<ELFT>(); + Addend += Sym.getSize(); + + // If the produced value is a constant, we just remember to write it + // when outputting this section. We also have to do it if the format + // uses Elf_Rel, since in that case the written value is the addend. + if (IsConstant) { + Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + continue; + } // If the output being produced is position independent, the final value // is still not known. In that case we still need some help from the // dynamic linker. We can however do better than just copying the incoming // relocation. We can process some of it and and just ask the dynamic // linker to add the load address. - if (!IsConstant) - In<ELFT>::RelaDyn->addReloc( - {Target->RelativeRel, &Sec, Offset, true, &Body, Addend}); - - // If the produced value is a constant, we just remember to write it - // when outputting this section. We also have to do it if the format - // uses Elf_Rel, since in that case the written value is the addend. - if (IsConstant || !RelTy::IsRela) - Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + if (Config->IsRela) { + InX::RelaDyn->addReloc( + {Target->RelativeRel, &Sec, Offset, true, &Sym, Addend}); + } else { + // In REL, addends are stored to the target section. + InX::RelaDyn->addReloc( + {Target->RelativeRel, &Sec, Offset, true, &Sym, 0}); + Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + } } } @@ -964,178 +1045,365 @@ template <class ELFT> void elf::scanRelocations(InputSectionBase &S) { scanRelocs<ELFT>(S, S.rels<ELFT>()); } +// Thunk Implementation +// +// Thunks (sometimes called stubs, veneers or branch islands) are small pieces +// of code that the linker inserts inbetween a caller and a callee. The thunks +// are added at link time rather than compile time as the decision on whether +// a thunk is needed, such as the caller and callee being out of range, can only +// be made at link time. +// +// It is straightforward to tell given the current state of the program when a +// thunk is needed for a particular call. The more difficult part is that +// the thunk needs to be placed in the program such that the caller can reach +// the thunk and the thunk can reach the callee; furthermore, adding thunks to +// the program alters addresses, which can mean more thunks etc. +// +// In lld we have a synthetic ThunkSection that can hold many Thunks. +// The decision to have a ThunkSection act as a container means that we can +// more easily handle the most common case of a single block of contiguous +// Thunks by inserting just a single ThunkSection. +// +// The implementation of Thunks in lld is split across these areas +// Relocations.cpp : Framework for creating and placing thunks +// Thunks.cpp : The code generated for each supported thunk +// Target.cpp : Target specific hooks that the framework uses to decide when +// a thunk is used +// Synthetic.cpp : Implementation of ThunkSection +// Writer.cpp : Iteratively call framework until no more Thunks added +// +// Thunk placement requirements: +// Mips LA25 thunks. These must be placed immediately before the callee section +// We can assume that the caller is in range of the Thunk. These are modelled +// by Thunks that return the section they must precede with +// getTargetInputSection(). +// +// ARM interworking and range extension thunks. These thunks must be placed +// within range of the caller. All implemented ARM thunks can always reach the +// callee as they use an indirect jump via a register that has no range +// restrictions. +// +// Thunk placement algorithm: +// For Mips LA25 ThunkSections; the placement is explicit, it has to be before +// getTargetInputSection(). +// +// For thunks that must be placed within range of the caller there are many +// possible choices given that the maximum range from the caller is usually +// much larger than the average InputSection size. Desirable properties include: +// - Maximize reuse of thunks by multiple callers +// - Minimize number of ThunkSections to simplify insertion +// - Handle impact of already added Thunks on addresses +// - Simple to understand and implement +// +// In lld for the first pass, we pre-create one or more ThunkSections per +// InputSectionDescription at Target specific intervals. A ThunkSection is +// placed so that the estimated end of the ThunkSection is within range of the +// start of the InputSectionDescription or the previous ThunkSection. For +// example: +// InputSectionDescription +// Section 0 +// ... +// Section N +// ThunkSection 0 +// Section N + 1 +// ... +// Section N + K +// Thunk Section 1 +// +// The intention is that we can add a Thunk to a ThunkSection that is well +// spaced enough to service a number of callers without having to do a lot +// of work. An important principle is that it is not an error if a Thunk cannot +// be placed in a pre-created ThunkSection; when this happens we create a new +// ThunkSection placed next to the caller. This allows us to handle the vast +// majority of thunks simply, but also handle rare cases where the branch range +// is smaller than the target specific spacing. +// +// The algorithm is expected to create all the thunks that are needed in a +// single pass, with a small number of programs needing a second pass due to +// the insertion of thunks in the first pass increasing the offset between +// callers and callees that were only just in range. +// +// A consequence of allowing new ThunkSections to be created outside of the +// pre-created ThunkSections is that in rare cases calls to Thunks that were in +// range in pass K, are out of range in some pass > K due to the insertion of +// more Thunks in between the caller and callee. When this happens we retarget +// the relocation back to the original target and create another Thunk. + +// Remove ThunkSections that are empty, this should only be the initial set +// precreated on pass 0. + // Insert the Thunks for OutputSection OS into their designated place // in the Sections vector, and recalculate the InputSection output section // offsets. // This may invalidate any output section offsets stored outside of InputSection -void ThunkCreator::mergeThunks() { - for (auto &KV : ThunkSections) { - std::vector<InputSection *> *ISR = KV.first; - std::vector<ThunkSection *> &Thunks = KV.second; - - // Order Thunks in ascending OutSecOff - auto ThunkCmp = [](const ThunkSection *A, const ThunkSection *B) { - return A->OutSecOff < B->OutSecOff; - }; - std::stable_sort(Thunks.begin(), Thunks.end(), ThunkCmp); - - // Merge sorted vectors of Thunks and InputSections by OutSecOff - std::vector<InputSection *> Tmp; - Tmp.reserve(ISR->size() + Thunks.size()); - auto MergeCmp = [](const InputSection *A, const InputSection *B) { - // std::merge requires a strict weak ordering. - if (A->OutSecOff < B->OutSecOff) - return true; - if (A->OutSecOff == B->OutSecOff) - // Check if Thunk is immediately before any specific Target InputSection - // for example Mips LA25 Thunks. - if (auto *TA = dyn_cast<ThunkSection>(A)) - if (TA && TA->getTargetInputSection() == B) +void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> OutputSections) { + forEachInputSectionDescription( + OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) { + if (ISD->ThunkSections.empty()) + return; + + // Remove any zero sized precreated Thunks. + llvm::erase_if(ISD->ThunkSections, + [](const std::pair<ThunkSection *, uint32_t> &TS) { + return TS.first->getSize() == 0; + }); + // ISD->ThunkSections contains all created ThunkSections, including + // those inserted in previous passes. Extract the Thunks created this + // pass and order them in ascending OutSecOff. + std::vector<ThunkSection *> NewThunks; + for (const std::pair<ThunkSection *, uint32_t> TS : ISD->ThunkSections) + if (TS.second == Pass) + NewThunks.push_back(TS.first); + std::stable_sort(NewThunks.begin(), NewThunks.end(), + [](const ThunkSection *A, const ThunkSection *B) { + return A->OutSecOff < B->OutSecOff; + }); + + // Merge sorted vectors of Thunks and InputSections by OutSecOff + std::vector<InputSection *> Tmp; + Tmp.reserve(ISD->Sections.size() + NewThunks.size()); + auto MergeCmp = [](const InputSection *A, const InputSection *B) { + // std::merge requires a strict weak ordering. + if (A->OutSecOff < B->OutSecOff) return true; - return false; - }; - std::merge(ISR->begin(), ISR->end(), Thunks.begin(), Thunks.end(), - std::back_inserter(Tmp), MergeCmp); - *ISR = std::move(Tmp); - } + if (A->OutSecOff == B->OutSecOff) { + auto *TA = dyn_cast<ThunkSection>(A); + auto *TB = dyn_cast<ThunkSection>(B); + // Check if Thunk is immediately before any specific Target + // InputSection for example Mips LA25 Thunks. + if (TA && TA->getTargetInputSection() == B) + return true; + if (TA && !TB && !TA->getTargetInputSection()) + // Place Thunk Sections without specific targets before + // non-Thunk Sections. + return true; + } + return false; + }; + std::merge(ISD->Sections.begin(), ISD->Sections.end(), + NewThunks.begin(), NewThunks.end(), std::back_inserter(Tmp), + MergeCmp); + ISD->Sections = std::move(Tmp); + }); } -static uint32_t findEndOfFirstNonExec(OutputSectionCommand &Cmd) { - for (BaseCommand *Base : Cmd.Commands) - if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) - for (auto *IS : ISD->Sections) - if ((IS->Flags & SHF_EXECINSTR) == 0) - return IS->OutSecOff + IS->getSize(); - return 0; -} +// Find or create a ThunkSection within the InputSectionDescription (ISD) that +// is in range of Src. An ISD maps to a range of InputSections described by a +// linker script section pattern such as { .text .text.* }. +ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *OS, InputSection *IS, + InputSectionDescription *ISD, + uint32_t Type, uint64_t Src) { + for (std::pair<ThunkSection *, uint32_t> TP : ISD->ThunkSections) { + ThunkSection *TS = TP.first; + uint64_t TSBase = OS->Addr + TS->OutSecOff; + uint64_t TSLimit = TSBase + TS->getSize(); + if (Target->inBranchRange(Type, Src, (Src > TSLimit) ? TSBase : TSLimit)) + return TS; + } -ThunkSection *ThunkCreator::getOSThunkSec(OutputSectionCommand *Cmd, - std::vector<InputSection *> *ISR) { - if (CurTS == nullptr) { - uint32_t Off = findEndOfFirstNonExec(*Cmd); - CurTS = addThunkSection(Cmd->Sec, ISR, Off); + // No suitable ThunkSection exists. This can happen when there is a branch + // with lower range than the ThunkSection spacing or when there are too + // many Thunks. Create a new ThunkSection as close to the InputSection as + // possible. Error if InputSection is so large we cannot place ThunkSection + // anywhere in Range. + uint64_t ThunkSecOff = IS->OutSecOff; + if (!Target->inBranchRange(Type, Src, OS->Addr + ThunkSecOff)) { + ThunkSecOff = IS->OutSecOff + IS->getSize(); + if (!Target->inBranchRange(Type, Src, OS->Addr + ThunkSecOff)) + fatal("InputSection too large for range extension thunk " + + IS->getObjMsg(Src - (OS->Addr + IS->OutSecOff))); } - return CurTS; + return addThunkSection(OS, ISD, ThunkSecOff); } -ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS, OutputSection *OS) { +// Add a Thunk that needs to be placed in a ThunkSection that immediately +// precedes its Target. +ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) { ThunkSection *TS = ThunkedSections.lookup(IS); if (TS) return TS; - auto *TOS = IS->getParent(); - // Find InputSectionRange within TOS that IS is in - OutputSectionCommand *C = Script->getCmd(TOS); - std::vector<InputSection *> *Range = nullptr; - for (BaseCommand *BC : C->Commands) + // Find InputSectionRange within Target Output Section (TOS) that the + // InputSection (IS) that we need to precede is in. + OutputSection *TOS = IS->getParent(); + for (BaseCommand *BC : TOS->SectionCommands) if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) { + if (ISD->Sections.empty()) + continue; InputSection *first = ISD->Sections.front(); InputSection *last = ISD->Sections.back(); if (IS->OutSecOff >= first->OutSecOff && IS->OutSecOff <= last->OutSecOff) { - Range = &ISD->Sections; + TS = addThunkSection(TOS, ISD, IS->OutSecOff); + ThunkedSections[IS] = TS; break; } } - TS = addThunkSection(TOS, Range, IS->OutSecOff); - ThunkedSections[IS] = TS; return TS; } +// Create one or more ThunkSections per OS that can be used to place Thunks. +// We attempt to place the ThunkSections using the following desirable +// properties: +// - Within range of the maximum number of callers +// - Minimise the number of ThunkSections +// +// We follow a simple but conservative heuristic to place ThunkSections at +// offsets that are multiples of a Target specific branch range. +// For an InputSectionRange that is smaller than the range, a single +// ThunkSection at the end of the range will do. +void ThunkCreator::createInitialThunkSections( + ArrayRef<OutputSection *> OutputSections) { + forEachInputSectionDescription( + OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) { + if (ISD->Sections.empty()) + return; + uint32_t ISLimit; + uint32_t PrevISLimit = ISD->Sections.front()->OutSecOff; + uint32_t ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing; + + for (const InputSection *IS : ISD->Sections) { + ISLimit = IS->OutSecOff + IS->getSize(); + if (ISLimit > ThunkUpperBound) { + addThunkSection(OS, ISD, PrevISLimit); + ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing; + } + PrevISLimit = ISLimit; + } + addThunkSection(OS, ISD, ISLimit); + }); +} + ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS, - std::vector<InputSection *> *ISR, + InputSectionDescription *ISD, uint64_t Off) { auto *TS = make<ThunkSection>(OS, Off); - ThunkSections[ISR].push_back(TS); + ISD->ThunkSections.push_back(std::make_pair(TS, Pass)); return TS; } -std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body, - uint32_t Type) { - auto Res = ThunkedSymbols.insert({&Body, std::vector<Thunk *>()}); +std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type, + uint64_t Src) { + auto Res = ThunkedSymbols.insert({&Sym, std::vector<Thunk *>()}); if (!Res.second) { - // Check existing Thunks for Body to see if they can be reused + // Check existing Thunks for Sym to see if they can be reused for (Thunk *ET : Res.first->second) - if (ET->isCompatibleWith(Type)) + if (ET->isCompatibleWith(Type) && + Target->inBranchRange(Type, Src, ET->ThunkSym->getVA())) return std::make_pair(ET, false); } // No existing compatible Thunk in range, create a new one - Thunk *T = addThunk(Type, Body); + Thunk *T = addThunk(Type, Sym); Res.first->second.push_back(T); return std::make_pair(T, true); } // Call Fn on every executable InputSection accessed via the linker script // InputSectionDescription::Sections. -void ThunkCreator::forEachExecInputSection( - ArrayRef<OutputSectionCommand *> OutputSections, - std::function<void(OutputSectionCommand *, std::vector<InputSection *> *, - InputSection *)> - Fn) { - for (OutputSectionCommand *Cmd : OutputSections) { - OutputSection *OS = Cmd->Sec; +void ThunkCreator::forEachInputSectionDescription( + ArrayRef<OutputSection *> OutputSections, + std::function<void(OutputSection *, InputSectionDescription *)> Fn) { + for (OutputSection *OS : OutputSections) { if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) continue; - for (BaseCommand *BC : Cmd->Commands) - if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) { - CurTS = nullptr; - for (InputSection *IS : ISD->Sections) - Fn(Cmd, &ISD->Sections, IS); - } + for (BaseCommand *BC : OS->SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) + Fn(OS, ISD); + } +} + +// Return true if the relocation target is an in range Thunk. +// Return false if the relocation is not to a Thunk. If the relocation target +// was originally to a Thunk, but is no longer in range we revert the +// relocation back to its original non-Thunk target. +bool ThunkCreator::normalizeExistingThunk(Relocation &Rel, uint64_t Src) { + if (Thunk *ET = Thunks.lookup(Rel.Sym)) { + if (Target->inBranchRange(Rel.Type, Src, Rel.Sym->getVA())) + return true; + Rel.Sym = &ET->Destination; + if (Rel.Sym->isInPlt()) + Rel.Expr = toPlt(Rel.Expr); } + return false; } // Process all relocations from the InputSections that have been assigned -// to OutputSections and redirect through Thunks if needed. +// to InputSectionDescriptions and redirect through Thunks if needed. The +// function should be called iteratively until it returns false. +// +// PreConditions: +// All InputSections that may need a Thunk are reachable from +// OutputSectionCommands. +// +// All OutputSections have an address and all InputSections have an offset +// within the OutputSection. // -// createThunks must be called after scanRelocs has created the Relocations for -// each InputSection. It must be called before the static symbol table is -// finalized. If any Thunks are added to an OutputSection the output section -// offsets of the InputSections will change. +// The offsets between caller (relocation place) and callee +// (relocation target) will not be modified outside of createThunks(). // -// FIXME: All Thunks are assumed to be in range of the relocation. Range -// extension Thunks are not yet supported. -bool ThunkCreator::createThunks( - ArrayRef<OutputSectionCommand *> OutputSections) { - if (Pass > 0) - ThunkSections.clear(); +// PostConditions: +// If return value is true then ThunkSections have been inserted into +// OutputSections. All relocations that needed a Thunk based on the information +// available to createThunks() on entry have been redirected to a Thunk. Note +// that adding Thunks changes offsets between caller and callee so more Thunks +// may be required. +// +// If return value is false then no more Thunks are needed, and createThunks has +// made no changes. If the target requires range extension thunks, currently +// ARM, then any future change in offset between caller and callee risks a +// relocation out of range error. +bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) { + bool AddressesChanged = false; + if (Pass == 0 && Target->ThunkSectionSpacing) + createInitialThunkSections(OutputSections); + else if (Pass == 10) + // With Thunk Size much smaller than branch range we expect to + // converge quickly; if we get to 10 something has gone wrong. + fatal("thunk creation not converged"); // Create all the Thunks and insert them into synthetic ThunkSections. The - // ThunkSections are later inserted back into the OutputSection. - + // ThunkSections are later inserted back into InputSectionDescriptions. // We separate the creation of ThunkSections from the insertion of the - // ThunkSections back into the OutputSection as ThunkSections are not always - // inserted into the same OutputSection as the caller. - forEachExecInputSection(OutputSections, [&](OutputSectionCommand *Cmd, - std::vector<InputSection *> *ISR, - InputSection *IS) { - for (Relocation &Rel : IS->Relocations) { - SymbolBody &Body = *Rel.Sym; - if (Thunks.find(&Body) != Thunks.end() || - !Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body)) - continue; - Thunk *T; - bool IsNew; - std::tie(T, IsNew) = getThunk(Body, Rel.Type); - if (IsNew) { - // Find or create a ThunkSection for the new Thunk - ThunkSection *TS; - if (auto *TIS = T->getTargetInputSection()) - TS = getISThunkSec(TIS, Cmd->Sec); - else - TS = getOSThunkSec(Cmd, ISR); - TS->addThunk(T); - Thunks[T->ThunkSym] = T; - } - // Redirect relocation to Thunk, we never go via the PLT to a Thunk - Rel.Sym = T->ThunkSym; - Rel.Expr = fromPlt(Rel.Expr); - } - }); + // ThunkSections as ThunkSections are not always inserted into the same + // InputSectionDescription as the caller. + forEachInputSectionDescription( + OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) { + for (InputSection *IS : ISD->Sections) + for (Relocation &Rel : IS->Relocations) { + uint64_t Src = OS->Addr + IS->OutSecOff + Rel.Offset; + + // If we are a relocation to an existing Thunk, check if it is + // still in range. If not then Rel will be altered to point to its + // original target so another Thunk can be generated. + if (Pass > 0 && normalizeExistingThunk(Rel, Src)) + continue; + + if (!Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Src, + *Rel.Sym)) + continue; + Thunk *T; + bool IsNew; + std::tie(T, IsNew) = getThunk(*Rel.Sym, Rel.Type, Src); + if (IsNew) { + AddressesChanged = true; + // Find or create a ThunkSection for the new Thunk + ThunkSection *TS; + if (auto *TIS = T->getTargetInputSection()) + TS = getISThunkSec(TIS); + else + TS = getISDThunkSec(OS, IS, ISD, Rel.Type, Src); + TS->addThunk(T); + Thunks[T->ThunkSym] = T; + } + // Redirect relocation to Thunk, we never go via the PLT to a Thunk + Rel.Sym = T->ThunkSym; + Rel.Expr = fromPlt(Rel.Expr); + } + }); // Merge all created synthetic ThunkSections back into OutputSection - mergeThunks(); + mergeThunks(OutputSections); ++Pass; - return !ThunkSections.empty(); + return AddressesChanged; } template void elf::scanRelocations<ELF32LE>(InputSectionBase &); diff --git a/ELF/Relocations.h b/ELF/Relocations.h index ea046d248474..2cc8adfa5985 100644 --- a/ELF/Relocations.h +++ b/ELF/Relocations.h @@ -10,23 +10,27 @@ #ifndef LLD_ELF_RELOCATIONS_H #define LLD_ELF_RELOCATIONS_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "llvm/ADT/DenseMap.h" #include <map> #include <vector> namespace lld { namespace elf { -class SymbolBody; +class Symbol; class InputSection; class InputSectionBase; class OutputSection; -struct OutputSectionCommand; +class OutputSection; + +// Represents a relocation type, such as R_X86_64_PC32 or R_ARM_THM_CALL. +typedef uint32_t RelType; // List of target-independent relocation types. Relocations read // from files are converted to these types so that the main code // doesn't have to know about architecture-specific details. enum RelExpr { + R_INVALID, R_ABS, R_ARM_SBREL, R_GOT, @@ -111,21 +115,22 @@ template <RelExpr... Exprs> bool isRelExprOneOf(RelExpr Expr) { // Architecture-neutral representation of relocation. struct Relocation { RelExpr Expr; - uint32_t Type; + RelType Type; uint64_t Offset; int64_t Addend; - SymbolBody *Sym; + Symbol *Sym; }; template <class ELFT> void scanRelocations(InputSectionBase &); class ThunkSection; class Thunk; +struct InputSectionDescription; class ThunkCreator { public: // Return true if Thunks have been added to OutputSections - bool createThunks(ArrayRef<OutputSectionCommand *> OutputSections); + bool createThunks(ArrayRef<OutputSection *> OutputSections); // The number of completed passes of createThunks this permits us // to do one time initialization on Pass 0 and put a limit on the @@ -133,40 +138,39 @@ public: uint32_t Pass = 0; private: - void mergeThunks(); - ThunkSection *getOSThunkSec(OutputSectionCommand *Cmd, - std::vector<InputSection *> *ISR); - ThunkSection *getISThunkSec(InputSection *IS, OutputSection *OS); - void forEachExecInputSection( - ArrayRef<OutputSectionCommand *> OutputSections, - std::function<void(OutputSectionCommand *, std::vector<InputSection *> *, - InputSection *)> - Fn); - std::pair<Thunk *, bool> getThunk(SymbolBody &Body, uint32_t Type); - ThunkSection *addThunkSection(OutputSection *OS, - std::vector<InputSection *> *, uint64_t Off); + void mergeThunks(ArrayRef<OutputSection *> OutputSections); + + ThunkSection *getISDThunkSec(OutputSection *OS, InputSection *IS, + InputSectionDescription *ISD, uint32_t Type, + uint64_t Src); + + ThunkSection *getISThunkSec(InputSection *IS); + + void createInitialThunkSections(ArrayRef<OutputSection *> OutputSections); + + void forEachInputSectionDescription( + ArrayRef<OutputSection *> OutputSections, + std::function<void(OutputSection *, InputSectionDescription *)> Fn); + + std::pair<Thunk *, bool> getThunk(Symbol &Sym, RelType Type, uint64_t Src); + + ThunkSection *addThunkSection(OutputSection *OS, InputSectionDescription *, + uint64_t Off); + + bool normalizeExistingThunk(Relocation &Rel, uint64_t Src); + // Record all the available Thunks for a Symbol - llvm::DenseMap<SymbolBody *, std::vector<Thunk *>> ThunkedSymbols; + llvm::DenseMap<Symbol *, std::vector<Thunk *>> ThunkedSymbols; // Find a Thunk from the Thunks symbol definition, we can use this to find // the Thunk from a relocation to the Thunks symbol definition. - llvm::DenseMap<SymbolBody *, Thunk *> Thunks; + llvm::DenseMap<Symbol *, Thunk *> Thunks; // Track InputSections that have an inline ThunkSection placed in front // an inline ThunkSection may have control fall through to the section below // so we need to make sure that there is only one of them. // The Mips LA25 Thunk is an example of an inline ThunkSection. llvm::DenseMap<InputSection *, ThunkSection *> ThunkedSections; - - // All the ThunkSections that we have created, organised by OutputSection - // will contain a mix of ThunkSections that have been created this pass, and - // ThunkSections that have been merged into the OutputSection on previous - // passes - std::map<std::vector<InputSection *> *, std::vector<ThunkSection *>> - ThunkSections; - - // The ThunkSection for this vector of InputSections - ThunkSection *CurTS; }; // Return a int64_t to make sure we get the sign extension out of the way as diff --git a/ELF/ScriptLexer.cpp b/ELF/ScriptLexer.cpp index 86720de3527c..9f33c16f36b0 100644 --- a/ELF/ScriptLexer.cpp +++ b/ELF/ScriptLexer.cpp @@ -33,7 +33,7 @@ //===----------------------------------------------------------------------===// #include "ScriptLexer.h" -#include "Error.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/Twine.h" using namespace llvm; @@ -75,19 +75,14 @@ ScriptLexer::ScriptLexer(MemoryBufferRef MB) { tokenize(MB); } // We don't want to record cascading errors. Keep only the first one. void ScriptLexer::setError(const Twine &Msg) { - if (Error) + if (errorCount()) return; - Error = true; - if (!Pos) { - error(getCurrentLocation() + ": " + Msg); - return; - } - - std::string S = getCurrentLocation() + ": "; - error(S + Msg); - error(S + getLine()); - error(S + std::string(getColumnNumber(), ' ') + "^"); + std::string S = (getCurrentLocation() + ": " + Msg).str(); + if (Pos) + S += "\n>>> " + getLine().str() + "\n>>> " + + std::string(getColumnNumber(), ' ') + "^"; + error(S); } // Split S into linker script tokens. @@ -164,18 +159,18 @@ StringRef ScriptLexer::skipSpace(StringRef S) { } // An erroneous token is handled as if it were the last token before EOF. -bool ScriptLexer::atEOF() { return Error || Tokens.size() == Pos; } +bool ScriptLexer::atEOF() { return errorCount() || Tokens.size() == Pos; } // Split a given string as an expression. // This function returns "3", "*" and "5" for "3*5" for example. static std::vector<StringRef> tokenizeExpr(StringRef S) { - StringRef Ops = "+-*/:"; // List of operators + StringRef Ops = "+-*/:!~"; // List of operators // Quoted strings are literal strings, so we don't want to split it. if (S.startswith("\"")) return {S}; - // Split S with +-*/ as separators. + // Split S with operators as separators. std::vector<StringRef> Ret; while (!S.empty()) { size_t E = S.find_first_of(Ops); @@ -190,9 +185,14 @@ static std::vector<StringRef> tokenizeExpr(StringRef S) { if (E != 0) Ret.push_back(S.substr(0, E)); - // Get the operator as a token. - Ret.push_back(S.substr(E, 1)); - S = S.substr(E + 1); + // Get the operator as a token. Keep != as one token. + if (S.substr(E).startswith("!=")) { + Ret.push_back(S.substr(E, 2)); + S = S.substr(E + 2); + } else { + Ret.push_back(S.substr(E, 1)); + S = S.substr(E + 1); + } } return Ret; } @@ -207,7 +207,7 @@ static std::vector<StringRef> tokenizeExpr(StringRef S) { // // This function may split the current token into multiple tokens. void ScriptLexer::maybeSplitExpr() { - if (!InExpr || Error || atEOF()) + if (!InExpr || errorCount() || atEOF()) return; std::vector<StringRef> V = tokenizeExpr(Tokens[Pos]); @@ -220,7 +220,7 @@ void ScriptLexer::maybeSplitExpr() { StringRef ScriptLexer::next() { maybeSplitExpr(); - if (Error) + if (errorCount()) return ""; if (atEOF()) { setError("unexpected EOF"); @@ -231,7 +231,7 @@ StringRef ScriptLexer::next() { StringRef ScriptLexer::peek() { StringRef Tok = next(); - if (Error) + if (errorCount()) return ""; Pos = Pos - 1; return Tok; @@ -260,7 +260,7 @@ bool ScriptLexer::consumeLabel(StringRef Tok) { void ScriptLexer::skip() { (void)next(); } void ScriptLexer::expect(StringRef Expect) { - if (Error) + if (errorCount()) return; StringRef Tok = next(); if (Tok != Expect) diff --git a/ELF/ScriptLexer.h b/ELF/ScriptLexer.h index 64d6d9204864..e7c8b28e49fd 100644 --- a/ELF/ScriptLexer.h +++ b/ELF/ScriptLexer.h @@ -10,7 +10,7 @@ #ifndef LLD_ELF_SCRIPT_LEXER_H #define LLD_ELF_SCRIPT_LEXER_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/MemoryBuffer.h" #include <utility> @@ -39,7 +39,6 @@ public: std::vector<StringRef> Tokens; bool InExpr = false; size_t Pos = 0; - bool Error = false; private: void maybeSplitExpr(); diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp index b3847081697c..d56500ae7dd8 100644 --- a/ELF/ScriptParser.cpp +++ b/ELF/ScriptParser.cpp @@ -17,13 +17,14 @@ #include "Driver.h" #include "InputSection.h" #include "LinkerScript.h" -#include "Memory.h" #include "OutputSections.h" #include "ScriptLexer.h" #include "Symbols.h" #include "Target.h" +#include "lld/Common/Memory.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Casting.h" @@ -52,10 +53,10 @@ public: void readLinkerScript(); void readVersionScript(); void readDynamicList(); + void readDefsym(StringRef Name); private: void addFile(StringRef Path); - OutputSection *checkSection(OutputSectionCommand *Cmd, StringRef Loccation); void readAsNeeded(); void readEntry(); @@ -67,17 +68,18 @@ private: void readOutputArch(); void readOutputFormat(); void readPhdrs(); + void readRegionAlias(); void readSearchDir(); void readSections(); void readVersion(); void readVersionScriptCommand(); SymbolAssignment *readAssignment(StringRef Name); - BytesDataCommand *readBytesDataCommand(StringRef Tok); + ByteCommand *readByteCommand(StringRef Tok); uint32_t readFill(); uint32_t parseFill(StringRef Tok); - void readSectionAddressType(OutputSectionCommand *Cmd); - OutputSectionCommand *readOutputSectionDescription(StringRef OutSec); + void readSectionAddressType(OutputSection *Cmd); + OutputSection *readOutputSectionDescription(StringRef OutSec); std::vector<StringRef> readOutputSectionPhdrs(); InputSectionDescription *readInputSectionDescription(StringRef Tok); StringMatcher readFilePatterns(); @@ -90,6 +92,8 @@ private: void readSort(); AssertCommand *readAssert(); Expr readAssertExpr(); + Expr readConstant(); + Expr getPageSize(); uint64_t readMemoryAssignment(StringRef, StringRef, StringRef); std::pair<uint32_t, uint32_t> readMemoryAttributes(); @@ -109,7 +113,11 @@ private: std::pair<std::vector<SymbolVersion>, std::vector<SymbolVersion>> readSymbols(); + // True if a script being read is in a subdirectory specified by -sysroot. bool IsUnderSysroot; + + // A set to detect an INCLUDE() cycle. + StringSet<> Seen; }; } // namespace @@ -131,7 +139,7 @@ static bool isUnderSysroot(StringRef Path) { // Some operations only support one non absolute value. Move the // absolute one to the right hand side for convenience. static void moveAbsRight(ExprValue &A, ExprValue &B) { - if (A.isAbsolute()) + if (A.Sec == nullptr || (A.ForceAbsolute && !B.isAbsolute())) std::swap(A, B); if (!B.isAbsolute()) error(A.Loc + ": at least one side of the expression must be absolute"); @@ -139,11 +147,11 @@ static void moveAbsRight(ExprValue &A, ExprValue &B) { static ExprValue add(ExprValue A, ExprValue B) { moveAbsRight(A, B); - return {A.Sec, A.ForceAbsolute, A.Val + B.getValue(), A.Loc}; + return {A.Sec, A.ForceAbsolute, A.getSectionOffset() + B.getValue(), A.Loc}; } static ExprValue sub(ExprValue A, ExprValue B) { - return {A.Sec, A.Val - B.getValue(), A.Loc}; + return {A.Sec, false, A.getSectionOffset() - B.getValue(), A.Loc}; } static ExprValue mul(ExprValue A, ExprValue B) { @@ -170,10 +178,24 @@ static ExprValue bitOr(ExprValue A, ExprValue B) { } void ScriptParser::readDynamicList() { + Config->HasDynamicList = true; expect("{"); - readAnonymousDeclaration(); - if (!atEOF()) + std::vector<SymbolVersion> Locals; + std::vector<SymbolVersion> Globals; + std::tie(Locals, Globals) = readSymbols(); + expect(";"); + + if (!atEOF()) { setError("EOF expected, but got " + next()); + return; + } + if (!Locals.empty()) { + setError("\"local:\" scope not supported in --dynamic-list"); + return; + } + + for (SymbolVersion V : Globals) + Config->DynamicList.push_back(V); } void ScriptParser::readVersionScript() { @@ -188,7 +210,7 @@ void ScriptParser::readVersionScriptCommand() { return; } - while (!atEOF() && !Error && peek() != "}") { + while (!atEOF() && !errorCount() && peek() != "}") { StringRef VerStr = next(); if (VerStr == "{") { setError("anonymous version definition is used in " @@ -213,7 +235,7 @@ void ScriptParser::readLinkerScript() { continue; if (Tok == "ASSERT") { - Script->Opt.Commands.push_back(readAssert()); + Script->SectionCommands.push_back(readAssert()); } else if (Tok == "ENTRY") { readEntry(); } else if (Tok == "EXTERN") { @@ -232,6 +254,8 @@ void ScriptParser::readLinkerScript() { readOutputFormat(); } else if (Tok == "PHDRS") { readPhdrs(); + } else if (Tok == "REGION_ALIAS") { + readRegionAlias(); } else if (Tok == "SEARCH_DIR") { readSearchDir(); } else if (Tok == "SECTIONS") { @@ -239,13 +263,21 @@ void ScriptParser::readLinkerScript() { } else if (Tok == "VERSION") { readVersion(); } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) { - Script->Opt.Commands.push_back(Cmd); + Script->SectionCommands.push_back(Cmd); } else { setError("unknown directive: " + Tok); } } } +void ScriptParser::readDefsym(StringRef Name) { + Expr E = readExpr(); + if (!atEOF()) + setError("EOF expected, but got " + next()); + SymbolAssignment *Cmd = make<SymbolAssignment>(Name, E, getCurrentLocation()); + Script->SectionCommands.push_back(Cmd); +} + void ScriptParser::addFile(StringRef S) { if (IsUnderSysroot && S.startswith("/")) { SmallString<128> PathData; @@ -256,7 +288,7 @@ void ScriptParser::addFile(StringRef S) { } } - if (sys::path::is_absolute(S)) { + if (S.startswith("/")) { Driver->addFile(S, /*WithLOption=*/false); } else if (S.startswith("=")) { if (Config->Sysroot.empty()) @@ -280,7 +312,7 @@ void ScriptParser::readAsNeeded() { expect("("); bool Orig = Config->AsNeeded; Config->AsNeeded = true; - while (!Error && !consume(")")) + while (!errorCount() && !consume(")")) addFile(unquote(next())); Config->AsNeeded = Orig; } @@ -296,13 +328,13 @@ void ScriptParser::readEntry() { void ScriptParser::readExtern() { expect("("); - while (!Error && !consume(")")) + while (!errorCount() && !consume(")")) Config->Undefined.push_back(next()); } void ScriptParser::readGroup() { expect("("); - while (!Error && !consume(")")) { + while (!errorCount() && !consume(")")) { if (consume("AS_NEEDED")) readAsNeeded(); else @@ -313,20 +345,17 @@ void ScriptParser::readGroup() { void ScriptParser::readInclude() { StringRef Tok = unquote(next()); - // https://sourceware.org/binutils/docs/ld/File-Commands.html: - // The file will be searched for in the current directory, and in any - // directory specified with the -L option. - if (sys::fs::exists(Tok)) { - if (Optional<MemoryBufferRef> MB = readFile(Tok)) - tokenize(*MB); + if (!Seen.insert(Tok).second) { + setError("there is a cycle in linker script INCLUDEs"); return; } - if (Optional<std::string> Path = findFromSearchPaths(Tok)) { + + if (Optional<std::string> Path = searchLinkerScript(Tok)) { if (Optional<MemoryBufferRef> MB = readFile(*Path)) tokenize(*MB); return; } - setError("cannot open " + Tok); + setError("cannot find linker script " + Tok); } void ScriptParser::readOutput() { @@ -341,7 +370,7 @@ void ScriptParser::readOutput() { void ScriptParser::readOutputArch() { // OUTPUT_ARCH is ignored for now. expect("("); - while (!Error && !consume(")")) + while (!errorCount() && !consume(")")) skip(); } @@ -360,28 +389,43 @@ void ScriptParser::readOutputFormat() { void ScriptParser::readPhdrs() { expect("{"); - while (!Error && !consume("}")) { - Script->Opt.PhdrsCommands.push_back( - {next(), PT_NULL, false, false, UINT_MAX, nullptr}); - PhdrsCommand &PhdrCmd = Script->Opt.PhdrsCommands.back(); - PhdrCmd.Type = readPhdrType(); + while (!errorCount() && !consume("}")) { + PhdrsCommand Cmd; + Cmd.Name = next(); + Cmd.Type = readPhdrType(); - while (!Error && !consume(";")) { + while (!errorCount() && !consume(";")) { if (consume("FILEHDR")) - PhdrCmd.HasFilehdr = true; + Cmd.HasFilehdr = true; else if (consume("PHDRS")) - PhdrCmd.HasPhdrs = true; + Cmd.HasPhdrs = true; else if (consume("AT")) - PhdrCmd.LMAExpr = readParenExpr(); + Cmd.LMAExpr = readParenExpr(); else if (consume("FLAGS")) - PhdrCmd.Flags = readParenExpr()().getValue(); + Cmd.Flags = readParenExpr()().getValue(); else setError("unexpected header attribute: " + next()); } + + Script->PhdrsCommands.push_back(Cmd); } } +void ScriptParser::readRegionAlias() { + expect("("); + StringRef Alias = unquote(next()); + expect(","); + StringRef Name = next(); + expect(")"); + + if (Script->MemoryRegions.count(Alias)) + setError("redefinition of memory region '" + Alias + "'"); + if (!Script->MemoryRegions.count(Name)) + setError("memory region '" + Name + "' is not defined"); + Script->MemoryRegions.insert({Alias, Script->MemoryRegions[Name]}); +} + void ScriptParser::readSearchDir() { expect("("); StringRef Tok = next(); @@ -391,7 +435,7 @@ void ScriptParser::readSearchDir() { } void ScriptParser::readSections() { - Script->Opt.HasSections = true; + Script->HasSectionsCommand = true; // -no-rosegment is used to avoid placing read only non-executable sections in // their own segment. We do the same if SECTIONS command is present in linker @@ -399,7 +443,7 @@ void ScriptParser::readSections() { Config->SingleRoRx = true; expect("{"); - while (!Error && !consume("}")) { + while (!errorCount() && !consume("}")) { StringRef Tok = next(); BaseCommand *Cmd = readProvideOrAssignment(Tok); if (!Cmd) { @@ -408,7 +452,7 @@ void ScriptParser::readSections() { else Cmd = readOutputSectionDescription(Tok); } - Script->Opt.Commands.push_back(Cmd); + Script->SectionCommands.push_back(Cmd); } } @@ -424,7 +468,7 @@ static int precedence(StringRef Op) { StringMatcher ScriptParser::readFilePatterns() { std::vector<StringRef> V; - while (!Error && !consume(")")) + while (!errorCount() && !consume(")")) V.push_back(next()); return StringMatcher(V); } @@ -456,7 +500,7 @@ SortSectionPolicy ScriptParser::readSortKind() { // any file but a.o, and section .baz in any file but b.o. std::vector<SectionPattern> ScriptParser::readInputSectionsList() { std::vector<SectionPattern> Ret; - while (!Error && peek() != ")") { + while (!errorCount() && peek() != ")") { StringMatcher ExcludeFilePat; if (consume("EXCLUDE_FILE")) { expect("("); @@ -464,7 +508,7 @@ std::vector<SectionPattern> ScriptParser::readInputSectionsList() { } std::vector<StringRef> V; - while (!Error && peek() != ")" && peek() != "EXCLUDE_FILE") + while (!errorCount() && peek() != ")" && peek() != "EXCLUDE_FILE") V.push_back(next()); if (!V.empty()) @@ -491,7 +535,7 @@ ScriptParser::readInputSectionRules(StringRef FilePattern) { auto *Cmd = make<InputSectionDescription>(FilePattern); expect("("); - while (!Error && !consume(")")) { + while (!errorCount() && !consume(")")) { SortSectionPolicy Outer = readSortKind(); SortSectionPolicy Inner = SortSectionPolicy::Default; std::vector<SectionPattern> V; @@ -529,7 +573,7 @@ ScriptParser::readInputSectionDescription(StringRef Tok) { StringRef FilePattern = next(); InputSectionDescription *Cmd = readInputSectionRules(FilePattern); expect(")"); - Script->Opt.KeptSections.push_back(Cmd); + Script->KeptSections.push_back(Cmd); return Cmd; } return readInputSectionRules(Tok); @@ -579,7 +623,7 @@ uint32_t ScriptParser::readFill() { // // https://sourceware.org/binutils/docs/ld/Output-Section-Address.html // https://sourceware.org/binutils/docs/ld/Output-Section-Type.html -void ScriptParser::readSectionAddressType(OutputSectionCommand *Cmd) { +void ScriptParser::readSectionAddressType(OutputSection *Cmd) { if (consume("(")) { if (consume("NOLOAD")) { expect(")"); @@ -599,21 +643,32 @@ void ScriptParser::readSectionAddressType(OutputSectionCommand *Cmd) { } } -OutputSectionCommand * -ScriptParser::readOutputSectionDescription(StringRef OutSec) { - OutputSectionCommand *Cmd = - Script->createOutputSectionCommand(OutSec, getCurrentLocation()); +static Expr checkAlignment(Expr E, std::string &Loc) { + return [=] { + uint64_t Alignment = std::max((uint64_t)1, E().getValue()); + if (!isPowerOf2_64(Alignment)) { + error(Loc + ": alignment must be power of 2"); + return (uint64_t)1; // Return a dummy value. + } + return Alignment; + }; +} + +OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) { + OutputSection *Cmd = + Script->createOutputSection(OutSec, getCurrentLocation()); if (peek() != ":") readSectionAddressType(Cmd); expect(":"); + std::string Location = getCurrentLocation(); if (consume("AT")) Cmd->LMAExpr = readParenExpr(); if (consume("ALIGN")) - Cmd->AlignExpr = readParenExpr(); + Cmd->AlignExpr = checkAlignment(readParenExpr(), Location); if (consume("SUBALIGN")) - Cmd->SubalignExpr = readParenExpr(); + Cmd->SubalignExpr = checkAlignment(readParenExpr(), Location); // Parse constraints. if (consume("ONLY_IF_RO")) @@ -622,16 +677,16 @@ ScriptParser::readOutputSectionDescription(StringRef OutSec) { Cmd->Constraint = ConstraintKind::ReadWrite; expect("{"); - while (!Error && !consume("}")) { + while (!errorCount() && !consume("}")) { StringRef Tok = next(); if (Tok == ";") { // Empty commands are allowed. Do nothing here. } else if (SymbolAssignment *Assign = readProvideOrAssignment(Tok)) { - Cmd->Commands.push_back(Assign); - } else if (BytesDataCommand *Data = readBytesDataCommand(Tok)) { - Cmd->Commands.push_back(Data); + Cmd->SectionCommands.push_back(Assign); + } else if (ByteCommand *Data = readByteCommand(Tok)) { + Cmd->SectionCommands.push_back(Data); } else if (Tok == "ASSERT") { - Cmd->Commands.push_back(readAssert()); + Cmd->SectionCommands.push_back(readAssert()); expect(";"); } else if (Tok == "CONSTRUCTORS") { // CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors @@ -642,7 +697,7 @@ ScriptParser::readOutputSectionDescription(StringRef OutSec) { } else if (Tok == "SORT") { readSort(); } else if (peek() == "(") { - Cmd->Commands.push_back(readInputSectionDescription(Tok)); + Cmd->SectionCommands.push_back(readInputSectionDescription(Tok)); } else { setError("unknown command " + Tok); } @@ -650,6 +705,8 @@ ScriptParser::readOutputSectionDescription(StringRef OutSec) { if (consume(">")) Cmd->MemoryRegionName = next(); + else if (peek().startswith(">")) + Cmd->MemoryRegionName = next().drop_front(); Cmd->Phdrs = readOutputSectionPhdrs(); @@ -712,7 +769,7 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef Name) { Expr E = readExpr(); if (Op == "+=") { std::string Loc = getCurrentLocation(); - E = [=] { return add(Script->getSymbolValue(Loc, Name), E()); }; + E = [=] { return add(Script->getSymbolValue(Name, Loc), E()); }; } return make<SymbolAssignment>(Name, E, getCurrentLocation()); } @@ -764,7 +821,7 @@ static Expr combine(StringRef Op, Expr L, Expr R) { // This is a part of the operator-precedence parser. This function // assumes that the remaining token stream starts with an operator. Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) { - while (!atEOF() && !Error) { + while (!atEOF() && !errorCount()) { // Read an operator and an expression. if (consume("?")) return readTernary(Lhs); @@ -790,13 +847,24 @@ Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) { return Lhs; } -uint64_t static getConstant(StringRef S) { +Expr ScriptParser::getPageSize() { + std::string Location = getCurrentLocation(); + return [=]() -> uint64_t { + if (Target) + return Target->PageSize; + error(Location + ": unable to calculate page size"); + return 4096; // Return a dummy value. + }; +} + +Expr ScriptParser::readConstant() { + StringRef S = readParenLiteral(); if (S == "COMMONPAGESIZE") - return Target->PageSize; + return getPageSize(); if (S == "MAXPAGESIZE") - return Config->MaxPageSize; - error("unknown constant: " + S); - return 0; + return [] { return Config->MaxPageSize; }; + setError("unknown constant: " + S); + return {}; } // Parses Tok as an integer. It recognizes hexadecimal (prefixed with @@ -812,10 +880,16 @@ static Optional<uint64_t> parseInt(StringRef Tok) { // Hexadecimal uint64_t Val; - if (Tok.startswith_lower("0x") && to_integer(Tok.substr(2), Val, 16)) + if (Tok.startswith_lower("0x")) { + if (!to_integer(Tok.substr(2), Val, 16)) + return None; return Val; - if (Tok.endswith_lower("H") && to_integer(Tok.drop_back(), Val, 16)) + } + if (Tok.endswith_lower("H")) { + if (!to_integer(Tok.drop_back(), Val, 16)) + return None; return Val; + } // Decimal if (Tok.endswith_lower("K")) { @@ -833,7 +907,7 @@ static Optional<uint64_t> parseInt(StringRef Tok) { return Val; } -BytesDataCommand *ScriptParser::readBytesDataCommand(StringRef Tok) { +ByteCommand *ScriptParser::readByteCommand(StringRef Tok) { int Size = StringSwitch<int>(Tok) .Case("BYTE", 1) .Case("SHORT", 2) @@ -842,8 +916,7 @@ BytesDataCommand *ScriptParser::readBytesDataCommand(StringRef Tok) { .Default(-1); if (Size == -1) return nullptr; - - return make<BytesDataCommand>(readParenExpr(), Size); + return make<ByteCommand>(readParenExpr(), Size); } StringRef ScriptParser::readParenLiteral() { @@ -853,14 +926,9 @@ StringRef ScriptParser::readParenLiteral() { return Tok; } -OutputSection *ScriptParser::checkSection(OutputSectionCommand *Cmd, - StringRef Location) { +static void checkIfExists(OutputSection *Cmd, StringRef Location) { if (Cmd->Location.empty() && Script->ErrorOnMissingSection) error(Location + ": undefined section " + Cmd->Name); - if (Cmd->Sec) - return Cmd->Sec; - static OutputSection Dummy("", 0, 0); - return &Dummy; } Expr ScriptParser::readPrimary() { @@ -871,6 +939,10 @@ Expr ScriptParser::readPrimary() { Expr E = readPrimary(); return [=] { return ~E().getValue(); }; } + if (consume("!")) { + Expr E = readPrimary(); + return [=] { return !E().getValue(); }; + } if (consume("-")) { Expr E = readPrimary(); return [=] { return -E().getValue(); }; @@ -891,18 +963,21 @@ Expr ScriptParser::readPrimary() { } if (Tok == "ADDR") { StringRef Name = readParenLiteral(); - OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); + OutputSection *Sec = Script->getOrCreateOutputSection(Name); return [=]() -> ExprValue { - return {checkSection(Cmd, Location), 0, Location}; + checkIfExists(Sec, Location); + return {Sec, false, 0, Location}; }; } if (Tok == "ALIGN") { expect("("); Expr E = readExpr(); - if (consume(")")) + if (consume(")")) { + E = checkAlignment(E, Location); return [=] { return alignTo(Script->getDot(), E().getValue()); }; + } expect(","); - Expr E2 = readExpr(); + Expr E2 = checkAlignment(readExpr(), Location); expect(")"); return [=] { ExprValue V = E(); @@ -912,22 +987,25 @@ Expr ScriptParser::readPrimary() { } if (Tok == "ALIGNOF") { StringRef Name = readParenLiteral(); - OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); - return [=] { return checkSection(Cmd, Location)->Alignment; }; + OutputSection *Cmd = Script->getOrCreateOutputSection(Name); + return [=] { + checkIfExists(Cmd, Location); + return Cmd->Alignment; + }; } if (Tok == "ASSERT") return readAssertExpr(); - if (Tok == "CONSTANT") { - StringRef Name = readParenLiteral(); - return [=] { return getConstant(Name); }; - } + if (Tok == "CONSTANT") + return readConstant(); if (Tok == "DATA_SEGMENT_ALIGN") { expect("("); Expr E = readExpr(); expect(","); readExpr(); expect(")"); - return [=] { return alignTo(Script->getDot(), E().getValue()); }; + return [=] { + return alignTo(Script->getDot(), std::max((uint64_t)1, E().getValue())); + }; } if (Tok == "DATA_SEGMENT_END") { expect("("); @@ -944,28 +1022,32 @@ Expr ScriptParser::readPrimary() { expect(","); readExpr(); expect(")"); - return [] { return alignTo(Script->getDot(), Target->PageSize); }; + Expr E = getPageSize(); + return [=] { return alignTo(Script->getDot(), E().getValue()); }; } if (Tok == "DEFINED") { StringRef Name = readParenLiteral(); - return [=] { return Script->isDefined(Name) ? 1 : 0; }; + return [=] { return Symtab->find(Name) ? 1 : 0; }; } if (Tok == "LENGTH") { StringRef Name = readParenLiteral(); - if (Script->Opt.MemoryRegions.count(Name) == 0) + if (Script->MemoryRegions.count(Name) == 0) setError("memory region not defined: " + Name); - return [=] { return Script->Opt.MemoryRegions[Name].Length; }; + return [=] { return Script->MemoryRegions[Name]->Length; }; } if (Tok == "LOADADDR") { StringRef Name = readParenLiteral(); - OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); - return [=] { return checkSection(Cmd, Location)->getLMA(); }; + OutputSection *Cmd = Script->getOrCreateOutputSection(Name); + return [=] { + checkIfExists(Cmd, Location); + return Cmd->getLMA(); + }; } if (Tok == "ORIGIN") { StringRef Name = readParenLiteral(); - if (Script->Opt.MemoryRegions.count(Name) == 0) + if (Script->MemoryRegions.count(Name) == 0) setError("memory region not defined: " + Name); - return [=] { return Script->Opt.MemoryRegions[Name].Origin; }; + return [=] { return Script->MemoryRegions[Name]->Origin; }; } if (Tok == "SEGMENT_START") { expect("("); @@ -977,18 +1059,18 @@ Expr ScriptParser::readPrimary() { } if (Tok == "SIZEOF") { StringRef Name = readParenLiteral(); - OutputSectionCommand *Cmd = Script->getOrCreateOutputSectionCommand(Name); + OutputSection *Cmd = Script->getOrCreateOutputSection(Name); // Linker script does not create an output section if its content is empty. // We want to allow SIZEOF(.foo) where .foo is a section which happened to // be empty. - return [=] { return Cmd->Sec ? Cmd->Sec->Size : 0; }; + return [=] { return Cmd->Size; }; } if (Tok == "SIZEOF_HEADERS") return [=] { return elf::getHeaderSize(); }; // Tok is the dot. if (Tok == ".") - return [=] { return Script->getSymbolValue(Location, Tok); }; + return [=] { return Script->getSymbolValue(Tok, Location); }; // Tok is a literal number. if (Optional<uint64_t> Val = parseInt(Tok)) @@ -997,8 +1079,8 @@ Expr ScriptParser::readPrimary() { // Tok is a symbol name. if (!isValidCIdentifier(Tok)) setError("malformed number: " + Tok); - Script->Opt.ReferencedSymbols.push_back(Tok); - return [=] { return Script->getSymbolValue(Location, Tok); }; + Script->ReferencedSymbols.push_back(Tok); + return [=] { return Script->getSymbolValue(Tok, Location); }; } Expr ScriptParser::readTernary(Expr Cond) { @@ -1017,7 +1099,7 @@ Expr ScriptParser::readParenExpr() { std::vector<StringRef> ScriptParser::readOutputSectionPhdrs() { std::vector<StringRef> Phdrs; - while (!Error && peek().startswith(":")) { + while (!errorCount() && peek().startswith(":")) { StringRef Tok = next(); Phdrs.push_back((Tok.size() == 1) ? next() : Tok.substr(1)); } @@ -1120,7 +1202,7 @@ ScriptParser::readSymbols() { std::vector<SymbolVersion> Globals; std::vector<SymbolVersion> *V = &Globals; - while (!Error) { + while (!errorCount()) { if (consume("}")) break; if (consumeLabel("local")) { @@ -1154,7 +1236,7 @@ std::vector<SymbolVersion> ScriptParser::readVersionExtern() { expect("{"); std::vector<SymbolVersion> Ret; - while (!Error && peek() != "}") { + while (!errorCount() && peek() != "}") { StringRef Tok = next(); bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok); Ret.push_back({unquote(Tok), IsCXX, HasWildcard}); @@ -1181,7 +1263,7 @@ uint64_t ScriptParser::readMemoryAssignment(StringRef S1, StringRef S2, // MEMORY { name [(attr)] : ORIGIN = origin, LENGTH = len ... } void ScriptParser::readMemory() { expect("{"); - while (!Error && !consume("}")) { + while (!errorCount() && !consume("}")) { StringRef Name = next(); uint32_t Flags = 0; @@ -1196,12 +1278,12 @@ void ScriptParser::readMemory() { expect(","); uint64_t Length = readMemoryAssignment("LENGTH", "len", "l"); - // Add the memory region to the region map (if it doesn't already exist). - auto It = Script->Opt.MemoryRegions.find(Name); - if (It != Script->Opt.MemoryRegions.end()) + // Add the memory region to the region map. + if (Script->MemoryRegions.count(Name)) setError("region '" + Name + "' already defined"); - else - Script->Opt.MemoryRegions[Name] = {Name, Origin, Length, Flags, NegFlags}; + MemoryRegion *MR = make<MemoryRegion>(); + *MR = {Name, Origin, Length, Flags, NegFlags}; + Script->MemoryRegions[Name] = MR; } } @@ -1245,3 +1327,7 @@ void elf::readVersionScript(MemoryBufferRef MB) { void elf::readDynamicList(MemoryBufferRef MB) { ScriptParser(MB).readDynamicList(); } + +void elf::readDefsym(StringRef Name, MemoryBufferRef MB) { + ScriptParser(MB).readDefsym(Name); +} diff --git a/ELF/ScriptParser.h b/ELF/ScriptParser.h index 02f3a2bd9d2c..d48d5aa2115e 100644 --- a/ELF/ScriptParser.h +++ b/ELF/ScriptParser.h @@ -10,7 +10,7 @@ #ifndef LLD_ELF_SCRIPT_PARSER_H #define LLD_ELF_SCRIPT_PARSER_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "llvm/Support/MemoryBuffer.h" namespace lld { @@ -25,6 +25,9 @@ void readVersionScript(MemoryBufferRef MB); void readDynamicList(MemoryBufferRef MB); +// Parses the defsym expression. +void readDefsym(StringRef Name, MemoryBufferRef MB); + } // namespace elf } // namespace lld diff --git a/ELF/Strings.cpp b/ELF/Strings.cpp index bca86384002d..0ef33a14bc3d 100644 --- a/ELF/Strings.cpp +++ b/ELF/Strings.cpp @@ -9,7 +9,7 @@ #include "Strings.h" #include "Config.h" -#include "Error.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" @@ -54,32 +54,9 @@ std::vector<uint8_t> elf::parseHex(StringRef S) { return Hex; } -static bool isAlpha(char C) { - return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z') || C == '_'; -} - -static bool isAlnum(char C) { return isAlpha(C) || ('0' <= C && C <= '9'); } - // Returns true if S is valid as a C language identifier. bool elf::isValidCIdentifier(StringRef S) { - return !S.empty() && isAlpha(S[0]) && - std::all_of(S.begin() + 1, S.end(), isAlnum); -} - -// Returns the demangled C++ symbol name for Name. -Optional<std::string> elf::demangle(StringRef Name) { - // itaniumDemangle can be used to demangle strings other than symbol - // names which do not necessarily start with "_Z". Name can be - // either a C or C++ symbol. Don't call itaniumDemangle if the name - // does not look like a C++ symbol name to avoid getting unexpected - // result for a C symbol that happens to match a mangled type name. - if (!Name.startswith("_Z")) - return None; - - char *Buf = itaniumDemangle(Name.str().c_str(), nullptr, nullptr, nullptr); - if (!Buf) - return None; - std::string S(Buf); - free(Buf); - return S; + return !S.empty() && (isAlpha(S[0]) || S[0] == '_') && + std::all_of(S.begin() + 1, S.end(), + [](char C) { return C == '_' || isAlnum(C); }); } diff --git a/ELF/Strings.h b/ELF/Strings.h index 68ccafa2ff17..5009df65f4c1 100644 --- a/ELF/Strings.h +++ b/ELF/Strings.h @@ -10,7 +10,7 @@ #ifndef LLD_ELF_STRINGS_H #define LLD_ELF_STRINGS_H -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/Optional.h" @@ -66,10 +66,6 @@ private: std::vector<llvm::GlobPattern> Patterns; }; -// Returns a demangled C++ symbol name. If Name is not a mangled -// name, it returns Optional::None. -llvm::Optional<std::string> demangle(StringRef Name); - inline ArrayRef<uint8_t> toArrayRef(StringRef S) { return {(const uint8_t *)S.data(), S.size()}; } diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index 0c932400f0ad..12509c9a1757 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -16,10 +16,12 @@ #include "SymbolTable.h" #include "Config.h" -#include "Error.h" #include "LinkerScript.h" -#include "Memory.h" #include "Symbols.h" +#include "SyntheticSections.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" #include "llvm/ADT/STLExtras.h" using namespace llvm; @@ -29,6 +31,16 @@ using namespace llvm::ELF; using namespace lld; using namespace lld::elf; +SymbolTable *elf::Symtab; + +static InputFile *getFirstElf() { + if (!ObjectFiles.empty()) + return ObjectFiles[0]; + if (!SharedFiles.empty()) + return SharedFiles[0]; + return nullptr; +} + // All input object files must be for the same architecture // (e.g. it does not make sense to link x86 object files with // MIPS object files.) This function checks for that error. @@ -46,15 +58,12 @@ template <class ELFT> static bool isCompatible(InputFile *F) { if (!Config->Emulation.empty()) error(toString(F) + " is incompatible with " + Config->Emulation); else - error(toString(F) + " is incompatible with " + toString(Config->FirstElf)); + error(toString(F) + " is incompatible with " + toString(getFirstElf())); return false; } // Add symbols in File to the symbol table. -template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) { - if (!Config->FirstElf && isa<ELFFileBase<ELFT>>(File)) - Config->FirstElf = File; - +template <class ELFT> void SymbolTable::addFile(InputFile *File) { if (!isCompatible<ELFT>(File)) return; @@ -72,7 +81,7 @@ template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) { } // Lazy object file - if (auto *F = dyn_cast<LazyObjectFile>(File)) { + if (auto *F = dyn_cast<LazyObjFile>(File)) { F->parse<ELFT>(); return; } @@ -84,7 +93,7 @@ template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) { if (auto *F = dyn_cast<SharedFile<ELFT>>(File)) { // DSOs are uniquified not by filename but by soname. F->parseSoName(); - if (ErrorCount || !SoNames.insert(F->SoName).second) + if (errorCount() || !SoNames.insert(F->SoName).second) return; SharedFiles.push_back(F); F->parseRest(); @@ -99,9 +108,8 @@ template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) { } // Regular object file - auto *F = cast<ObjectFile<ELFT>>(File); - ObjectFiles.push_back(F); - F->parse(ComdatGroups); + ObjectFiles.push_back(File); + cast<ObjFile<ELFT>>(File)->parse(ComdatGroups); } // This function is where all the optimizations of link-time @@ -111,7 +119,7 @@ template <class ELFT> void SymbolTable<ELFT>::addFile(InputFile *File) { // using LLVM functions and replaces bitcode symbols with the results. // Because all bitcode files that consist of a program are passed // to the compiler at once, it can do whole-program optimization. -template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() { +template <class ELFT> void SymbolTable::addCombinedLTOObject() { if (BitcodeFiles.empty()) return; @@ -121,82 +129,77 @@ template <class ELFT> void SymbolTable<ELFT>::addCombinedLTOObject() { LTO->add(*F); for (InputFile *File : LTO->compile()) { - ObjectFile<ELFT> *Obj = cast<ObjectFile<ELFT>>(File); DenseSet<CachedHashStringRef> DummyGroups; - Obj->parse(DummyGroups); - ObjectFiles.push_back(Obj); + cast<ObjFile<ELFT>>(File)->parse(DummyGroups); + ObjectFiles.push_back(File); } } template <class ELFT> -DefinedRegular *SymbolTable<ELFT>::addAbsolute(StringRef Name, - uint8_t Visibility, - uint8_t Binding) { - Symbol *Sym = - addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Binding, nullptr, nullptr); - return cast<DefinedRegular>(Sym->body()); -} - -// Add Name as an "ignored" symbol. An ignored symbol is a regular -// linker-synthesized defined symbol, but is only defined if needed. -template <class ELFT> -DefinedRegular *SymbolTable<ELFT>::addIgnored(StringRef Name, - uint8_t Visibility) { - SymbolBody *S = find(Name); - if (!S || S->isInCurrentDSO()) - return nullptr; - return addAbsolute(Name, Visibility); +Defined *SymbolTable::addAbsolute(StringRef Name, uint8_t Visibility, + uint8_t Binding) { + Symbol *Sym = addRegular<ELFT>(Name, Visibility, STT_NOTYPE, 0, 0, Binding, + nullptr, nullptr); + return cast<Defined>(Sym); } // Set a flag for --trace-symbol so that we can print out a log message // if a new symbol with the same name is inserted into the symbol table. -template <class ELFT> void SymbolTable<ELFT>::trace(StringRef Name) { - Symtab.insert({CachedHashStringRef(Name), {-1, true}}); +void SymbolTable::trace(StringRef Name) { + SymMap.insert({CachedHashStringRef(Name), -1}); } // Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM. // Used to implement --wrap. -template <class ELFT> void SymbolTable<ELFT>::addSymbolWrap(StringRef Name) { - SymbolBody *B = find(Name); - if (!B) +template <class ELFT> void SymbolTable::addSymbolWrap(StringRef Name) { + Symbol *Sym = find(Name); + if (!Sym) return; - Symbol *Sym = B->symbol(); - Symbol *Real = addUndefined(Saver.save("__real_" + Name)); - Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name)); + Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name)); + Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name)); + WrappedSymbols.push_back({Sym, Real, Wrap}); - // Tell LTO not to eliminate this symbol - Wrap->IsUsedInRegularObj = true; - - Config->RenamedSymbols[Real] = {Sym, Real->Binding}; - Config->RenamedSymbols[Sym] = {Wrap, Sym->Binding}; -} - -// Creates alias for symbol. Used to implement --defsym=ALIAS=SYM. -template <class ELFT> -void SymbolTable<ELFT>::addSymbolAlias(StringRef Alias, StringRef Name) { - SymbolBody *B = find(Name); - if (!B) { - error("-defsym: undefined symbol: " + Name); - return; - } - Symbol *Sym = B->symbol(); - Symbol *AliasSym = addUndefined(Alias); + // We want to tell LTO not to inline symbols to be overwritten + // because LTO doesn't know the final symbol contents after renaming. + Real->CanInline = false; + Sym->CanInline = false; - // Tell LTO not to eliminate this symbol + // Tell LTO not to eliminate these symbols. Sym->IsUsedInRegularObj = true; - Config->RenamedSymbols[AliasSym] = {Sym, AliasSym->Binding}; + Wrap->IsUsedInRegularObj = true; } -// Apply symbol renames created by -wrap and -defsym. The renames are created -// before LTO in addSymbolWrap() and addSymbolAlias() to have a chance to inform -// LTO (if LTO is running) not to include these symbols in IPO. Now that the +// Apply symbol renames created by -wrap. The renames are created +// before LTO in addSymbolWrap() to have a chance to inform LTO (if +// LTO is running) not to include these symbols in IPO. Now that the // symbols are finalized, we can perform the replacement. -template <class ELFT> void SymbolTable<ELFT>::applySymbolRenames() { - for (auto &KV : Config->RenamedSymbols) { - Symbol *Dst = KV.first; - Symbol *Src = KV.second.Target; - Dst->body()->copy(Src->body()); - Dst->Binding = KV.second.OriginalBinding; +void SymbolTable::applySymbolWrap() { + // This function rotates 3 symbols: + // + // __real_sym becomes sym + // sym becomes __wrap_sym + // __wrap_sym becomes __real_sym + // + // The last part is special in that we don't want to change what references to + // __wrap_sym point to, we just want have __real_sym in the symbol table. + + for (WrappedSymbol &W : WrappedSymbols) { + // First, make a copy of __real_sym. + Symbol *Real = nullptr; + if (W.Real->isDefined()) { + Real = (Symbol *)make<SymbolUnion>(); + memcpy(Real, W.Real, sizeof(SymbolUnion)); + } + + // Replace __real_sym with sym and sym with __wrap_sym. + memcpy(W.Real, W.Sym, sizeof(SymbolUnion)); + memcpy(W.Sym, W.Wrap, sizeof(SymbolUnion)); + + // We now have two copies of __wrap_sym. Drop one. + W.Wrap->IsUsedInRegularObj = false; + + if (Real) + SymVector.push_back(Real); } } @@ -209,48 +212,50 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { } // Find an existing symbol or create and insert a new one. -template <class ELFT> -std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) { +std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) { // <name>@@<version> means the symbol is the default version. In that // case <name>@@<version> will be used to resolve references to <name>. - size_t Pos = Name.find("@@"); - if (Pos != StringRef::npos) + // + // Since this is a hot path, the following string search code is + // optimized for speed. StringRef::find(char) is much faster than + // StringRef::find(StringRef). + size_t Pos = Name.find('@'); + if (Pos != StringRef::npos && Pos + 1 < Name.size() && Name[Pos + 1] == '@') Name = Name.take_front(Pos); - auto P = Symtab.insert( - {CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)}); - SymIndex &V = P.first->second; + auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()}); + int &SymIndex = P.first->second; bool IsNew = P.second; + bool Traced = false; - if (V.Idx == -1) { - IsNew = true; - V = SymIndex((int)SymVector.size(), true); + if (SymIndex == -1) { + SymIndex = SymVector.size(); + IsNew = Traced = true; } Symbol *Sym; if (IsNew) { - Sym = make<Symbol>(); + Sym = (Symbol *)make<SymbolUnion>(); Sym->InVersionScript = false; - Sym->Binding = STB_WEAK; Sym->Visibility = STV_DEFAULT; Sym->IsUsedInRegularObj = false; Sym->ExportDynamic = false; - Sym->Traced = V.Traced; + Sym->CanInline = true; + Sym->Traced = Traced; Sym->VersionId = Config->DefaultSymbolVersion; SymVector.push_back(Sym); } else { - Sym = SymVector[V.Idx]; + Sym = SymVector[SymIndex]; } return {Sym, IsNew}; } // Find an existing symbol or create and insert a new one, then apply the given // attributes. -template <class ELFT> -std::pair<Symbol *, bool> -SymbolTable<ELFT>::insert(StringRef Name, uint8_t Type, uint8_t Visibility, - bool CanOmitFromDynSym, InputFile *File) { - bool IsUsedInRegularObj = !File || File->kind() == InputFile::ObjectKind; +std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, uint8_t Type, + uint8_t Visibility, + bool CanOmitFromDynSym, + InputFile *File) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); @@ -261,32 +266,30 @@ SymbolTable<ELFT>::insert(StringRef Name, uint8_t Type, uint8_t Visibility, if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic)) S->ExportDynamic = true; - if (IsUsedInRegularObj) + if (!File || File->kind() == InputFile::ObjKind) S->IsUsedInRegularObj = true; - if (!WasInserted && S->body()->Type != SymbolBody::UnknownType && - ((Type == STT_TLS) != S->body()->isTls())) { - error("TLS attribute mismatch: " + toString(*S->body()) + - "\n>>> defined in " + toString(S->body()->File) + - "\n>>> defined in " + toString(File)); + if (!WasInserted && S->Type != Symbol::UnknownType && + ((Type == STT_TLS) != S->isTls())) { + error("TLS attribute mismatch: " + toString(*S) + "\n>>> defined in " + + toString(S->File) + "\n>>> defined in " + toString(File)); } return {S, WasInserted}; } -template <class ELFT> Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name) { - return addUndefined(Name, /*IsLocal=*/false, STB_GLOBAL, STV_DEFAULT, - /*Type*/ 0, - /*CanOmitFromDynSym*/ false, /*File*/ nullptr); +template <class ELFT> Symbol *SymbolTable::addUndefined(StringRef Name) { + return addUndefined<ELFT>(Name, STB_GLOBAL, STV_DEFAULT, + /*Type*/ 0, + /*CanOmitFromDynSym*/ false, /*File*/ nullptr); } static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; } template <class ELFT> -Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal, - uint8_t Binding, uint8_t StOther, - uint8_t Type, bool CanOmitFromDynSym, - InputFile *File) { +Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding, + uint8_t StOther, uint8_t Type, + bool CanOmitFromDynSym, InputFile *File) { Symbol *S; bool WasInserted; uint8_t Visibility = getVisibility(StOther); @@ -294,26 +297,24 @@ Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal, insert(Name, Type, Visibility, CanOmitFromDynSym, File); // An undefined symbol with non default visibility must be satisfied // in the same DSO. - if (WasInserted || - (isa<SharedSymbol>(S->body()) && Visibility != STV_DEFAULT)) { - S->Binding = Binding; - replaceBody<Undefined>(S, Name, IsLocal, StOther, Type, File); + if (WasInserted || (isa<SharedSymbol>(S) && Visibility != STV_DEFAULT)) { + replaceSymbol<Undefined>(S, File, Name, Binding, StOther, Type); return S; } + if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK)) + S->Binding = Binding; if (Binding != STB_WEAK) { - SymbolBody *B = S->body(); - if (B->isShared() || B->isLazy() || B->isUndefined()) - S->Binding = Binding; - if (auto *SS = dyn_cast<SharedSymbol>(B)) - cast<SharedFile<ELFT>>(SS->File)->IsUsed = true; + if (auto *SS = dyn_cast<SharedSymbol>(S)) + if (!Config->GcSections) + SS->getFile<ELFT>()->IsNeeded = true; } - if (auto *L = dyn_cast<Lazy>(S->body())) { - // An undefined weak will not fetch archive members, but we have to remember - // its type. See also comment in addLazyArchive. - if (S->isWeak()) + if (auto *L = dyn_cast<Lazy>(S)) { + // An undefined weak will not fetch archive members. See comment on Lazy in + // Symbols.h for the details. + if (Binding == STB_WEAK) L->Type = Type; else if (InputFile *F = L->fetch()) - addFile(F); + addFile<ELFT>(F); } return S; } @@ -325,11 +326,11 @@ Symbol *SymbolTable<ELFT>::addUndefined(StringRef Name, bool IsLocal, // .symver foo,foo@@@VER // we can delete this hack. static int compareVersion(Symbol *S, StringRef Name) { - if (Name.find("@@") != StringRef::npos && - S->body()->getName().find("@@") == StringRef::npos) + bool A = Name.contains("@@"); + bool B = S->getName().contains("@@"); + if (A && !B) return 1; - if (Name.find("@@") == StringRef::npos && - S->body()->getName().find("@@") != StringRef::npos) + if (!A && B) return -1; return 0; } @@ -341,13 +342,10 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding, StringRef Name) { if (WasInserted) return 1; - SymbolBody *Body = S->body(); - if (!Body->isInCurrentDSO()) + if (!S->isDefined()) return 1; - if (int R = compareVersion(S, Name)) return R; - if (Binding == STB_WEAK) return -1; if (S->isWeak()) @@ -358,22 +356,18 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding, // We have a new non-common defined symbol with the specified binding. Return 1 // if the new symbol should win, -1 if the new symbol should lose, or 0 if there // is a conflict. If the new symbol wins, also update the binding. -template <typename ELFT> static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding, - bool IsAbsolute, typename ELFT::uint Value, + bool IsAbsolute, uint64_t Value, StringRef Name) { - if (int Cmp = compareDefined(S, WasInserted, Binding, Name)) { - if (Cmp > 0) - S->Binding = Binding; + if (int Cmp = compareDefined(S, WasInserted, Binding, Name)) return Cmp; - } - SymbolBody *B = S->body(); - if (isa<DefinedCommon>(B)) { - // Non-common symbols take precedence over common symbols. - if (Config->WarnCommon) - warn("common " + S->body()->getName() + " is overridden"); - return 1; - } else if (auto *R = dyn_cast<DefinedRegular>(B)) { + if (auto *R = dyn_cast<Defined>(S)) { + if (R->Section && isa<BssSection>(R->Section)) { + // Non-common symbols take precedence over common symbols. + if (Config->WarnCommon) + warn("common " + S->getName() + " is overridden"); + return 1; + } if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute && R->Value == Value) return -1; @@ -381,34 +375,39 @@ static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding, return 0; } -template <class ELFT> -Symbol *SymbolTable<ELFT>::addCommon(StringRef N, uint64_t Size, - uint32_t Alignment, uint8_t Binding, - uint8_t StOther, uint8_t Type, - InputFile *File) { +Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment, + uint8_t Binding, uint8_t StOther, uint8_t Type, + InputFile *File) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther), /*CanOmitFromDynSym*/ false, File); int Cmp = compareDefined(S, WasInserted, Binding, N); if (Cmp > 0) { - S->Binding = Binding; - replaceBody<DefinedCommon>(S, N, Size, Alignment, StOther, Type, File); + auto *Bss = make<BssSection>("COMMON", Size, Alignment); + Bss->File = File; + Bss->Live = !Config->GcSections; + InputSections.push_back(Bss); + + replaceSymbol<Defined>(S, File, N, Binding, StOther, Type, 0, Size, Bss); } else if (Cmp == 0) { - auto *C = dyn_cast<DefinedCommon>(S->body()); - if (!C) { + auto *D = cast<Defined>(S); + auto *Bss = dyn_cast_or_null<BssSection>(D->Section); + if (!Bss) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) - warn("common " + S->body()->getName() + " is overridden"); + warn("common " + S->getName() + " is overridden"); return S; } if (Config->WarnCommon) - warn("multiple common of " + S->body()->getName()); + warn("multiple common of " + D->getName()); - Alignment = C->Alignment = std::max(C->Alignment, Alignment); - if (Size > C->Size) - replaceBody<DefinedCommon>(S, N, Size, Alignment, StOther, Type, File); + Bss->Alignment = std::max(Bss->Alignment, Alignment); + if (Size > Bss->Size) { + D->File = Bss->File = File; + D->Size = Bss->Size = Size; + } } return S; } @@ -420,17 +419,17 @@ static void warnOrError(const Twine &Msg) { error(Msg); } -static void reportDuplicate(SymbolBody *Sym, InputFile *NewFile) { +static void reportDuplicate(Symbol *Sym, InputFile *NewFile) { warnOrError("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " + toString(Sym->File) + "\n>>> defined in " + toString(NewFile)); } template <class ELFT> -static void reportDuplicate(SymbolBody *Sym, InputSectionBase *ErrSec, +static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec, typename ELFT::uint ErrOffset) { - DefinedRegular *D = dyn_cast<DefinedRegular>(Sym); - if (!D || !D->Section || !ErrSec) { - reportDuplicate(Sym, ErrSec ? ErrSec->getFile<ELFT>() : nullptr); + Defined *D = cast<Defined>(Sym); + if (!D->Section || !ErrSec) { + reportDuplicate(Sym, ErrSec ? ErrSec->File : nullptr); return; } @@ -442,10 +441,10 @@ static void reportDuplicate(SymbolBody *Sym, InputSectionBase *ErrSec, // >>> defined at baz.c:563 // >>> baz.o in archive libbaz.a auto *Sec1 = cast<InputSectionBase>(D->Section); - std::string Src1 = Sec1->getSrcMsg<ELFT>(D->Value); - std::string Obj1 = Sec1->getObjMsg<ELFT>(D->Value); - std::string Src2 = ErrSec->getSrcMsg<ELFT>(ErrOffset); - std::string Obj2 = ErrSec->getObjMsg<ELFT>(ErrOffset); + std::string Src1 = Sec1->getSrcMsg<ELFT>(*Sym, D->Value); + std::string Obj1 = Sec1->getObjMsg(D->Value); + std::string Src2 = ErrSec->getSrcMsg<ELFT>(*Sym, ErrOffset); + std::string Obj2 = ErrSec->getObjMsg(ErrOffset); std::string Msg = "duplicate symbol: " + toString(*Sym) + "\n>>> defined at "; if (!Src1.empty()) @@ -458,29 +457,28 @@ static void reportDuplicate(SymbolBody *Sym, InputSectionBase *ErrSec, } template <typename ELFT> -Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t StOther, - uint8_t Type, uint64_t Value, - uint64_t Size, uint8_t Binding, - SectionBase *Section, InputFile *File) { +Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type, + uint64_t Value, uint64_t Size, uint8_t Binding, + SectionBase *Section, InputFile *File) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther), /*CanOmitFromDynSym*/ false, File); - int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding, - Section == nullptr, Value, Name); + int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, Section == nullptr, + Value, Name); if (Cmp > 0) - replaceBody<DefinedRegular>(S, Name, /*IsLocal=*/false, StOther, Type, - Value, Size, Section, File); + replaceSymbol<Defined>(S, File, Name, Binding, StOther, Type, Value, Size, + Section); else if (Cmp == 0) - reportDuplicate<ELFT>(S->body(), - dyn_cast_or_null<InputSectionBase>(Section), Value); + reportDuplicate<ELFT>(S, dyn_cast_or_null<InputSectionBase>(Section), + Value); return S; } template <typename ELFT> -void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *File, StringRef Name, - const Elf_Sym &Sym, - const typename ELFT::Verdef *Verdef) { +void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> *File, + const typename ELFT::Sym &Sym, uint32_t Alignment, + uint32_t VerdefIndex) { // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT // as the visibility, which will leave the visibility in the symbol table // unchanged. @@ -492,110 +490,102 @@ void SymbolTable<ELFT>::addShared(SharedFile<ELFT> *File, StringRef Name, if (Sym.getVisibility() == STV_DEFAULT) S->ExportDynamic = true; - SymbolBody *Body = S->body(); // An undefined symbol with non default visibility must be satisfied // in the same DSO. - if (WasInserted || - (isa<Undefined>(Body) && Body->getVisibility() == STV_DEFAULT)) { - replaceBody<SharedSymbol>(S, File, Name, Sym.st_other, Sym.getType(), &Sym, - Verdef); - if (!S->isWeak()) - File->IsUsed = true; + if (WasInserted || ((S->isUndefined() || S->isLazy()) && + S->getVisibility() == STV_DEFAULT)) { + uint8_t Binding = S->Binding; + replaceSymbol<SharedSymbol>(S, File, Name, Sym.getBinding(), Sym.st_other, + Sym.getType(), Sym.st_value, Sym.st_size, + Alignment, VerdefIndex); + if (!WasInserted) { + S->Binding = Binding; + if (!S->isWeak() && !Config->GcSections) + File->IsNeeded = true; + } } } -template <class ELFT> -Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, uint8_t Binding, - uint8_t StOther, uint8_t Type, - bool CanOmitFromDynSym, BitcodeFile *F) { +Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding, + uint8_t StOther, uint8_t Type, + bool CanOmitFromDynSym, BitcodeFile *F) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, F); - int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding, - /*IsAbs*/ false, /*Value*/ 0, Name); + int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, + /*IsAbs*/ false, /*Value*/ 0, Name); if (Cmp > 0) - replaceBody<DefinedRegular>(S, Name, /*IsLocal=*/false, StOther, Type, 0, 0, - nullptr, F); + replaceSymbol<Defined>(S, F, Name, Binding, StOther, Type, 0, 0, nullptr); else if (Cmp == 0) - reportDuplicate(S->body(), F); + reportDuplicate(S, F); return S; } -template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) { - auto It = Symtab.find(CachedHashStringRef(Name)); - if (It == Symtab.end()) +Symbol *SymbolTable::find(StringRef Name) { + auto It = SymMap.find(CachedHashStringRef(Name)); + if (It == SymMap.end()) return nullptr; - SymIndex V = It->second; - if (V.Idx == -1) + if (It->second == -1) return nullptr; - return SymVector[V.Idx]->body(); -} - -template <class ELFT> -SymbolBody *SymbolTable<ELFT>::findInCurrentDSO(StringRef Name) { - if (SymbolBody *S = find(Name)) - if (S->isInCurrentDSO()) - return S; - return nullptr; + return SymVector[It->second]; } template <class ELFT> -Symbol *SymbolTable<ELFT>::addLazyArchive(ArchiveFile *F, - const object::Archive::Symbol Sym) { +Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile *F, + const object::Archive::Symbol Sym) { Symbol *S; bool WasInserted; - StringRef Name = Sym.getName(); std::tie(S, WasInserted) = insert(Name); if (WasInserted) { - replaceBody<LazyArchive>(S, *F, Sym, SymbolBody::UnknownType); + replaceSymbol<LazyArchive>(S, F, Sym, Symbol::UnknownType); return S; } - if (!S->body()->isUndefined()) + if (!S->isUndefined()) return S; - // Weak undefined symbols should not fetch members from archives. If we were - // to keep old symbol we would not know that an archive member was available - // if a strong undefined symbol shows up afterwards in the link. If a strong - // undefined symbol never shows up, this lazy symbol will get to the end of - // the link and must be treated as the weak undefined one. We already marked - // this symbol as used when we added it to the symbol table, but we also need - // to preserve its type. FIXME: Move the Type field to Symbol. + // An undefined weak will not fetch archive members. See comment on Lazy in + // Symbols.h for the details. if (S->isWeak()) { - replaceBody<LazyArchive>(S, *F, Sym, S->body()->Type); + replaceSymbol<LazyArchive>(S, F, Sym, S->Type); + S->Binding = STB_WEAK; return S; } std::pair<MemoryBufferRef, uint64_t> MBInfo = F->getMember(&Sym); if (!MBInfo.first.getBuffer().empty()) - addFile(createObjectFile(MBInfo.first, F->getName(), MBInfo.second)); + addFile<ELFT>(createObjectFile(MBInfo.first, F->getName(), MBInfo.second)); return S; } template <class ELFT> -void SymbolTable<ELFT>::addLazyObject(StringRef Name, LazyObjectFile &Obj) { +void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { - replaceBody<LazyObject>(S, Name, Obj, SymbolBody::UnknownType); + replaceSymbol<LazyObject>(S, &Obj, Name, Symbol::UnknownType); return; } - if (!S->body()->isUndefined()) + if (!S->isUndefined()) return; // See comment for addLazyArchive above. if (S->isWeak()) - replaceBody<LazyObject>(S, Name, Obj, S->body()->Type); + replaceSymbol<LazyObject>(S, &Obj, Name, S->Type); else if (InputFile *F = Obj.fetch()) - addFile(F); + addFile<ELFT>(F); } -// Process undefined (-u) flags by loading lazy symbols named by those flags. -template <class ELFT> void SymbolTable<ELFT>::scanUndefinedFlags() { - for (StringRef S : Config->Undefined) - if (auto *L = dyn_cast_or_null<Lazy>(find(S))) +// If we already saw this symbol, force loading its file. +template <class ELFT> void SymbolTable::fetchIfLazy(StringRef Name) { + if (Symbol *B = find(Name)) { + // Mark the symbol not to be eliminated by LTO + // even if it is a bitcode symbol. + B->IsUsedInRegularObj = true; + if (auto *L = dyn_cast_or_null<Lazy>(B)) if (InputFile *File = L->fetch()) - addFile(File); + addFile<ELFT>(File); + } } // This function takes care of the case in which shared libraries depend on @@ -605,19 +595,19 @@ template <class ELFT> void SymbolTable<ELFT>::scanUndefinedFlags() { // We need to put such symbols to the main program's .dynsym so that // shared libraries can find them. // Except this, we ignore undefined symbols in DSOs. -template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() { - for (SharedFile<ELFT> *File : SharedFiles) { - for (StringRef U : File->getUndefinedSymbols()) { - SymbolBody *Sym = find(U); +template <class ELFT> void SymbolTable::scanShlibUndefined() { + for (InputFile *F : SharedFiles) { + for (StringRef U : cast<SharedFile<ELFT>>(F)->getUndefinedSymbols()) { + Symbol *Sym = find(U); if (!Sym || !Sym->isDefined()) continue; - Sym->symbol()->ExportDynamic = true; + Sym->ExportDynamic = true; // If -dynamic-list is given, the default version is set to // VER_NDX_LOCAL, which prevents a symbol to be exported via .dynsym. // Set to VER_NDX_GLOBAL so the symbol will be handled as if it were // specified by -dynamic-list. - Sym->symbol()->VersionId = VER_NDX_GLOBAL; + Sym->VersionId = VER_NDX_GLOBAL; } } } @@ -635,37 +625,32 @@ template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() { // other than trying to match a pattern against all demangled symbols. // So, if "extern C++" feature is used, we need to demangle all known // symbols. -template <class ELFT> -StringMap<std::vector<SymbolBody *>> &SymbolTable<ELFT>::getDemangledSyms() { +StringMap<std::vector<Symbol *>> &SymbolTable::getDemangledSyms() { if (!DemangledSyms) { DemangledSyms.emplace(); for (Symbol *Sym : SymVector) { - SymbolBody *B = Sym->body(); - if (B->isUndefined()) + if (!Sym->isDefined()) continue; - if (Optional<std::string> S = demangle(B->getName())) - (*DemangledSyms)[*S].push_back(B); + if (Optional<std::string> S = demangleItanium(Sym->getName())) + (*DemangledSyms)[*S].push_back(Sym); else - (*DemangledSyms)[B->getName()].push_back(B); + (*DemangledSyms)[Sym->getName()].push_back(Sym); } } return *DemangledSyms; } -template <class ELFT> -std::vector<SymbolBody *> SymbolTable<ELFT>::findByVersion(SymbolVersion Ver) { +std::vector<Symbol *> SymbolTable::findByVersion(SymbolVersion Ver) { if (Ver.IsExternCpp) return getDemangledSyms().lookup(Ver.Name); - if (SymbolBody *B = find(Ver.Name)) - if (!B->isUndefined()) + if (Symbol *B = find(Ver.Name)) + if (B->isDefined()) return {B}; return {}; } -template <class ELFT> -std::vector<SymbolBody *> -SymbolTable<ELFT>::findAllByVersion(SymbolVersion Ver) { - std::vector<SymbolBody *> Res; +std::vector<Symbol *> SymbolTable::findAllByVersion(SymbolVersion Ver) { + std::vector<Symbol *> Res; StringMatcher M(Ver.Name); if (Ver.IsExternCpp) { @@ -675,18 +660,16 @@ SymbolTable<ELFT>::findAllByVersion(SymbolVersion Ver) { return Res; } - for (Symbol *Sym : SymVector) { - SymbolBody *B = Sym->body(); - if (!B->isUndefined() && M.match(B->getName())) - Res.push_back(B); - } + for (Symbol *Sym : SymVector) + if (Sym->isDefined() && M.match(Sym->getName())) + Res.push_back(Sym); return Res; } // If there's only one anonymous version definition in a version // script file, the script does not actually define any symbol version, // but just specifies symbols visibilities. -template <class ELFT> void SymbolTable<ELFT>::handleAnonymousVersion() { +void SymbolTable::handleAnonymousVersion() { for (SymbolVersion &Ver : Config->VersionScriptGlobals) assignExactVersion(Ver, VER_NDX_GLOBAL, "global"); for (SymbolVersion &Ver : Config->VersionScriptGlobals) @@ -697,17 +680,33 @@ template <class ELFT> void SymbolTable<ELFT>::handleAnonymousVersion() { assignWildcardVersion(Ver, VER_NDX_LOCAL); } +// Handles -dynamic-list. +void SymbolTable::handleDynamicList() { + for (SymbolVersion &Ver : Config->DynamicList) { + std::vector<Symbol *> Syms; + if (Ver.HasWildcard) + Syms = findAllByVersion(Ver); + else + Syms = findByVersion(Ver); + + for (Symbol *B : Syms) { + if (!Config->Shared) + B->ExportDynamic = true; + else if (B->includeInDynsym()) + B->IsPreemptible = true; + } + } +} + // Set symbol versions to symbols. This function handles patterns // containing no wildcard characters. -template <class ELFT> -void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver, - uint16_t VersionId, - StringRef VersionName) { +void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId, + StringRef VersionName) { if (Ver.HasWildcard) return; // Get a list of symbols which we need to assign the version to. - std::vector<SymbolBody *> Syms = findByVersion(Ver); + std::vector<Symbol *> Syms = findByVersion(Ver); if (Syms.empty()) { if (Config->NoUndefinedVersion) error("version script assignment of '" + VersionName + "' to symbol '" + @@ -716,14 +715,13 @@ void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver, } // Assign the version. - for (SymbolBody *B : Syms) { + for (Symbol *Sym : Syms) { // Skip symbols containing version info because symbol versions // specified by symbol names take precedence over version scripts. // See parseSymbolVersion(). - if (B->getName().find('@') != StringRef::npos) + if (Sym->getName().contains('@')) continue; - Symbol *Sym = B->symbol(); if (Sym->InVersionScript) warn("duplicate symbol '" + Ver.Name + "' in version script"); Sym->VersionId = VersionId; @@ -731,25 +729,24 @@ void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver, } } -template <class ELFT> -void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver, - uint16_t VersionId) { +void SymbolTable::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) { if (!Ver.HasWildcard) return; // Exact matching takes precendence over fuzzy matching, // so we set a version to a symbol only if no version has been assigned // to the symbol. This behavior is compatible with GNU. - for (SymbolBody *B : findAllByVersion(Ver)) - if (B->symbol()->VersionId == Config->DefaultSymbolVersion) - B->symbol()->VersionId = VersionId; + for (Symbol *B : findAllByVersion(Ver)) + if (B->VersionId == Config->DefaultSymbolVersion) + B->VersionId = VersionId; } // This function processes version scripts by updating VersionId // member of symbols. -template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() { +void SymbolTable::scanVersionScript() { // Handle edge cases first. handleAnonymousVersion(); + handleDynamicList(); // Now we have version definitions, so we need to set version ids to symbols. // Each version definition has a glob pattern, and all symbols that match @@ -773,10 +770,92 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() { // can contain versions in the form of <name>@<version>. // Let them parse and update their names to exclude version suffix. for (Symbol *Sym : SymVector) - Sym->body()->parseSymbolVersion(); -} - -template class elf::SymbolTable<ELF32LE>; -template class elf::SymbolTable<ELF32BE>; -template class elf::SymbolTable<ELF64LE>; -template class elf::SymbolTable<ELF64BE>; + Sym->parseSymbolVersion(); +} + +template void SymbolTable::addSymbolWrap<ELF32LE>(StringRef); +template void SymbolTable::addSymbolWrap<ELF32BE>(StringRef); +template void SymbolTable::addSymbolWrap<ELF64LE>(StringRef); +template void SymbolTable::addSymbolWrap<ELF64BE>(StringRef); + +template Symbol *SymbolTable::addUndefined<ELF32LE>(StringRef); +template Symbol *SymbolTable::addUndefined<ELF32BE>(StringRef); +template Symbol *SymbolTable::addUndefined<ELF64LE>(StringRef); +template Symbol *SymbolTable::addUndefined<ELF64BE>(StringRef); + +template Symbol *SymbolTable::addUndefined<ELF32LE>(StringRef, uint8_t, uint8_t, + uint8_t, bool, InputFile *); +template Symbol *SymbolTable::addUndefined<ELF32BE>(StringRef, uint8_t, uint8_t, + uint8_t, bool, InputFile *); +template Symbol *SymbolTable::addUndefined<ELF64LE>(StringRef, uint8_t, uint8_t, + uint8_t, bool, InputFile *); +template Symbol *SymbolTable::addUndefined<ELF64BE>(StringRef, uint8_t, uint8_t, + uint8_t, bool, InputFile *); + +template void SymbolTable::addCombinedLTOObject<ELF32LE>(); +template void SymbolTable::addCombinedLTOObject<ELF32BE>(); +template void SymbolTable::addCombinedLTOObject<ELF64LE>(); +template void SymbolTable::addCombinedLTOObject<ELF64BE>(); + +template Symbol *SymbolTable::addRegular<ELF32LE>(StringRef, uint8_t, uint8_t, + uint64_t, uint64_t, uint8_t, + SectionBase *, InputFile *); +template Symbol *SymbolTable::addRegular<ELF32BE>(StringRef, uint8_t, uint8_t, + uint64_t, uint64_t, uint8_t, + SectionBase *, InputFile *); +template Symbol *SymbolTable::addRegular<ELF64LE>(StringRef, uint8_t, uint8_t, + uint64_t, uint64_t, uint8_t, + SectionBase *, InputFile *); +template Symbol *SymbolTable::addRegular<ELF64BE>(StringRef, uint8_t, uint8_t, + uint64_t, uint64_t, uint8_t, + SectionBase *, InputFile *); + +template Defined *SymbolTable::addAbsolute<ELF32LE>(StringRef, uint8_t, + uint8_t); +template Defined *SymbolTable::addAbsolute<ELF32BE>(StringRef, uint8_t, + uint8_t); +template Defined *SymbolTable::addAbsolute<ELF64LE>(StringRef, uint8_t, + uint8_t); +template Defined *SymbolTable::addAbsolute<ELF64BE>(StringRef, uint8_t, + uint8_t); + +template Symbol * +SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile *, + const object::Archive::Symbol); +template Symbol * +SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile *, + const object::Archive::Symbol); +template Symbol * +SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile *, + const object::Archive::Symbol); +template Symbol * +SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile *, + const object::Archive::Symbol); + +template void SymbolTable::addLazyObject<ELF32LE>(StringRef, LazyObjFile &); +template void SymbolTable::addLazyObject<ELF32BE>(StringRef, LazyObjFile &); +template void SymbolTable::addLazyObject<ELF64LE>(StringRef, LazyObjFile &); +template void SymbolTable::addLazyObject<ELF64BE>(StringRef, LazyObjFile &); + +template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> *, + const typename ELF32LE::Sym &, + uint32_t Alignment, uint32_t); +template void SymbolTable::addShared<ELF32BE>(StringRef, SharedFile<ELF32BE> *, + const typename ELF32BE::Sym &, + uint32_t Alignment, uint32_t); +template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile<ELF64LE> *, + const typename ELF64LE::Sym &, + uint32_t Alignment, uint32_t); +template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> *, + const typename ELF64BE::Sym &, + uint32_t Alignment, uint32_t); + +template void SymbolTable::fetchIfLazy<ELF32LE>(StringRef); +template void SymbolTable::fetchIfLazy<ELF32BE>(StringRef); +template void SymbolTable::fetchIfLazy<ELF64LE>(StringRef); +template void SymbolTable::fetchIfLazy<ELF64BE>(StringRef); + +template void SymbolTable::scanShlibUndefined<ELF32LE>(); +template void SymbolTable::scanShlibUndefined<ELF32BE>(); +template void SymbolTable::scanShlibUndefined<ELF64LE>(); +template void SymbolTable::scanShlibUndefined<ELF64BE>(); diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h index 4ba101fa5d50..738311c089db 100644 --- a/ELF/SymbolTable.h +++ b/ELF/SymbolTable.h @@ -18,8 +18,8 @@ namespace lld { namespace elf { - -struct Symbol; +class Defined; +class SectionBase; // SymbolTable is a bucket of all known symbols, including defined, // undefined, or lazy symbols (the last one is symbols in archive @@ -33,45 +33,44 @@ struct Symbol; // to replace the lazy symbol. The logic is implemented in the // add*() functions, which are called by input files as they are parsed. There // is one add* function per symbol type. -template <class ELFT> class SymbolTable { - typedef typename ELFT::Sym Elf_Sym; - +class SymbolTable { public: - void addFile(InputFile *File); - void addCombinedLTOObject(); - void addSymbolAlias(StringRef Alias, StringRef Name); - void addSymbolWrap(StringRef Name); - void applySymbolRenames(); + template <class ELFT> void addFile(InputFile *File); + template <class ELFT> void addCombinedLTOObject(); + template <class ELFT> void addSymbolWrap(StringRef Name); + void applySymbolWrap(); ArrayRef<Symbol *> getSymbols() const { return SymVector; } - ArrayRef<ObjectFile<ELFT> *> getObjectFiles() const { return ObjectFiles; } - ArrayRef<BinaryFile *> getBinaryFiles() const { return BinaryFiles; } - ArrayRef<SharedFile<ELFT> *> getSharedFiles() const { return SharedFiles; } - DefinedRegular *addAbsolute(StringRef Name, - uint8_t Visibility = llvm::ELF::STV_HIDDEN, - uint8_t Binding = llvm::ELF::STB_GLOBAL); - DefinedRegular *addIgnored(StringRef Name, - uint8_t Visibility = llvm::ELF::STV_HIDDEN); - - Symbol *addUndefined(StringRef Name); - Symbol *addUndefined(StringRef Name, bool IsLocal, uint8_t Binding, - uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym, - InputFile *File); + template <class ELFT> + Defined *addAbsolute(StringRef Name, + uint8_t Visibility = llvm::ELF::STV_HIDDEN, + uint8_t Binding = llvm::ELF::STB_GLOBAL); + template <class ELFT> Symbol *addUndefined(StringRef Name); + template <class ELFT> + Symbol *addUndefined(StringRef Name, uint8_t Binding, uint8_t StOther, + uint8_t Type, bool CanOmitFromDynSym, InputFile *File); + template <class ELFT> Symbol *addRegular(StringRef Name, uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, uint8_t Binding, SectionBase *Section, InputFile *File); - void addShared(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym, - const typename ELFT::Verdef *Verdef); + template <class ELFT> + void addShared(StringRef Name, SharedFile<ELFT> *F, + const typename ELFT::Sym &Sym, uint32_t Alignment, + uint32_t VerdefIndex); + + template <class ELFT> + Symbol *addLazyArchive(StringRef Name, ArchiveFile *F, + const llvm::object::Archive::Symbol S); + + template <class ELFT> void addLazyObject(StringRef Name, LazyObjFile &Obj); - Symbol *addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S); - void addLazyObject(StringRef Name, LazyObjectFile &Obj); Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File); - Symbol *addCommon(StringRef N, uint64_t Size, uint32_t Alignment, + Symbol *addCommon(StringRef Name, uint64_t Size, uint32_t Alignment, uint8_t Binding, uint8_t StOther, uint8_t Type, InputFile *File); @@ -80,31 +79,27 @@ public: uint8_t Visibility, bool CanOmitFromDynSym, InputFile *File); - void scanUndefinedFlags(); - void scanShlibUndefined(); + template <class ELFT> void fetchIfLazy(StringRef Name); + template <class ELFT> void scanShlibUndefined(); void scanVersionScript(); - SymbolBody *find(StringRef Name); - SymbolBody *findInCurrentDSO(StringRef Name); + Symbol *find(StringRef Name); void trace(StringRef Name); + void handleDynamicList(); + private: - std::vector<SymbolBody *> findByVersion(SymbolVersion Ver); - std::vector<SymbolBody *> findAllByVersion(SymbolVersion Ver); + std::vector<Symbol *> findByVersion(SymbolVersion Ver); + std::vector<Symbol *> findAllByVersion(SymbolVersion Ver); + void defsym(Symbol *Dst, Symbol *Src); - llvm::StringMap<std::vector<SymbolBody *>> &getDemangledSyms(); + llvm::StringMap<std::vector<Symbol *>> &getDemangledSyms(); void handleAnonymousVersion(); void assignExactVersion(SymbolVersion Ver, uint16_t VersionId, StringRef VersionName); void assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId); - struct SymIndex { - SymIndex(int Idx, bool Traced) : Idx(Idx), Traced(Traced) {} - int Idx : 31; - unsigned Traced : 1; - }; - // The order the global symbols are in is not defined. We can use an arbitrary // order, but it has to be reproducible. That is true even when cross linking. // The default hashing of StringRef produces different results on 32 and 64 @@ -112,7 +107,7 @@ private: // but a bit inefficient. // FIXME: Experiment with passing in a custom hashing or sorting the symbols // once symbol resolution is finished. - llvm::DenseMap<llvm::CachedHashStringRef, SymIndex> Symtab; + llvm::DenseMap<llvm::CachedHashStringRef, int> SymMap; std::vector<Symbol *> SymVector; // Comdat groups define "link once" sections. If two comdat groups have the @@ -120,11 +115,6 @@ private: // is used to uniquify them. llvm::DenseSet<llvm::CachedHashStringRef> ComdatGroups; - std::vector<ObjectFile<ELFT> *> ObjectFiles; - std::vector<SharedFile<ELFT> *> SharedFiles; - std::vector<BitcodeFile *> BitcodeFiles; - std::vector<BinaryFile *> BinaryFiles; - // Set of .so files to not link the same shared object file more than once. llvm::DenseSet<StringRef> SoNames; @@ -132,15 +122,22 @@ private: // This mapping is 1:N because two symbols with different versions // can have the same name. We use this map to handle "extern C++ {}" // directive in version scripts. - llvm::Optional<llvm::StringMap<std::vector<SymbolBody *>>> DemangledSyms; + llvm::Optional<llvm::StringMap<std::vector<Symbol *>>> DemangledSyms; + + struct WrappedSymbol { + Symbol *Sym; + Symbol *Real; + Symbol *Wrap; + }; + + // For -wrap. + std::vector<WrappedSymbol> WrappedSymbols; // For LTO. std::unique_ptr<BitcodeCompiler> LTO; }; -template <class ELFT> struct Symtab { static SymbolTable<ELFT> *X; }; -template <class ELFT> SymbolTable<ELFT> *Symtab<ELFT>::X; - +extern SymbolTable *Symtab; } // namespace elf } // namespace lld diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index c69007e781a6..ab42fcd51a81 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -8,15 +8,15 @@ //===----------------------------------------------------------------------===// #include "Symbols.h" -#include "Error.h" #include "InputFiles.h" #include "InputSection.h" #include "OutputSections.h" -#include "Strings.h" #include "SyntheticSections.h" #include "Target.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Strings.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Path.h" #include <cstring> @@ -28,25 +28,23 @@ using namespace llvm::ELF; using namespace lld; using namespace lld::elf; -DefinedRegular *ElfSym::Bss; -DefinedRegular *ElfSym::Etext1; -DefinedRegular *ElfSym::Etext2; -DefinedRegular *ElfSym::Edata1; -DefinedRegular *ElfSym::Edata2; -DefinedRegular *ElfSym::End1; -DefinedRegular *ElfSym::End2; -DefinedRegular *ElfSym::GlobalOffsetTable; -DefinedRegular *ElfSym::MipsGp; -DefinedRegular *ElfSym::MipsGpDisp; -DefinedRegular *ElfSym::MipsLocalGp; - -static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) { - switch (Body.kind()) { - case SymbolBody::DefinedRegularKind: { - auto &D = cast<DefinedRegular>(Body); +Defined *ElfSym::Bss; +Defined *ElfSym::Etext1; +Defined *ElfSym::Etext2; +Defined *ElfSym::Edata1; +Defined *ElfSym::Edata2; +Defined *ElfSym::End1; +Defined *ElfSym::End2; +Defined *ElfSym::GlobalOffsetTable; +Defined *ElfSym::MipsGp; +Defined *ElfSym::MipsGpDisp; +Defined *ElfSym::MipsLocalGp; + +static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { + switch (Sym.kind()) { + case Symbol::DefinedKind: { + auto &D = cast<Defined>(Sym); SectionBase *IS = D.Section; - if (auto *ISB = dyn_cast_or_null<InputSectionBase>(IS)) - IS = ISB->Repl; // According to the ELF spec reference to a local symbol from outside // the group are not allowed. Unfortunately .eh_frame breaks that rule @@ -59,6 +57,7 @@ static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) { if (!IS) return D.Value; + IS = IS->Repl; uint64_t Offset = D.Value; // An object in an SHF_MERGE section might be referenced via a @@ -99,139 +98,85 @@ static uint64_t getSymVA(const SymbolBody &Body, int64_t &Addend) { } return VA; } - case SymbolBody::DefinedCommonKind: - if (!Config->DefineCommon) - return 0; - return InX::Common->getParent()->Addr + InX::Common->OutSecOff + - cast<DefinedCommon>(Body).Offset; - case SymbolBody::SharedKind: { - auto &SS = cast<SharedSymbol>(Body); - if (SS.NeedsCopy) - return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff + - SS.CopyRelSecOff; + case Symbol::SharedKind: { + auto &SS = cast<SharedSymbol>(Sym); + if (SS.CopyRelSec) + return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff; if (SS.NeedsPltAddr) - return Body.getPltVA(); + return Sym.getPltVA(); return 0; } - case SymbolBody::UndefinedKind: + case Symbol::UndefinedKind: return 0; - case SymbolBody::LazyArchiveKind: - case SymbolBody::LazyObjectKind: - assert(Body.symbol()->IsUsedInRegularObj && "lazy symbol reached writer"); + case Symbol::LazyArchiveKind: + case Symbol::LazyObjectKind: + assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer"); return 0; } llvm_unreachable("invalid symbol kind"); } -SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, - uint8_t Type) - : SymbolKind(K), NeedsCopy(false), NeedsPltAddr(false), IsLocal(IsLocal), - IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), - IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {} - -// Returns true if a symbol can be replaced at load-time by a symbol -// with the same name defined in other ELF executable or DSO. -bool SymbolBody::isPreemptible() const { - if (isLocal()) - return false; - - // Shared symbols resolve to the definition in the DSO. The exceptions are - // symbols with copy relocations (which resolve to .bss) or preempt plt - // entries (which resolve to that plt entry). - if (isShared()) - return !NeedsCopy && !NeedsPltAddr; - - // That's all that can be preempted in a non-DSO. - if (!Config->Shared) - return false; - - // Only symbols that appear in dynsym can be preempted. - if (!symbol()->includeInDynsym()) - return false; - - // Only default visibility symbols can be preempted. - if (symbol()->Visibility != STV_DEFAULT) - return false; - - // -Bsymbolic means that definitions are not preempted. - if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc())) - return !isDefined(); - return true; -} - -// Overwrites all attributes with Other's so that this symbol becomes -// an alias to Other. This is useful for handling some options such as -// --wrap. -void SymbolBody::copy(SymbolBody *Other) { - memcpy(symbol()->Body.buffer, Other->symbol()->Body.buffer, - sizeof(Symbol::Body)); +// Returns true if this is a weak undefined symbol. +bool Symbol::isUndefWeak() const { + // See comment on Lazy in Symbols.h for the details. + return isWeak() && (isUndefined() || isLazy()); } -uint64_t SymbolBody::getVA(int64_t Addend) const { +uint64_t Symbol::getVA(int64_t Addend) const { uint64_t OutVA = getSymVA(*this, Addend); return OutVA + Addend; } -uint64_t SymbolBody::getGotVA() const { - return InX::Got->getVA() + getGotOffset(); -} +uint64_t Symbol::getGotVA() const { return InX::Got->getVA() + getGotOffset(); } -uint64_t SymbolBody::getGotOffset() const { +uint64_t Symbol::getGotOffset() const { return GotIndex * Target->GotEntrySize; } -uint64_t SymbolBody::getGotPltVA() const { +uint64_t Symbol::getGotPltVA() const { if (this->IsInIgot) return InX::IgotPlt->getVA() + getGotPltOffset(); return InX::GotPlt->getVA() + getGotPltOffset(); } -uint64_t SymbolBody::getGotPltOffset() const { +uint64_t Symbol::getGotPltOffset() const { return GotPltIndex * Target->GotPltEntrySize; } -uint64_t SymbolBody::getPltVA() const { +uint64_t Symbol::getPltVA() const { if (this->IsInIplt) return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize; return InX::Plt->getVA() + Target->PltHeaderSize + PltIndex * Target->PltEntrySize; } -template <class ELFT> typename ELFT::uint SymbolBody::getSize() const { - if (const auto *C = dyn_cast<DefinedCommon>(this)) - return C->Size; - if (const auto *DR = dyn_cast<DefinedRegular>(this)) +uint64_t Symbol::getSize() const { + if (const auto *DR = dyn_cast<Defined>(this)) return DR->Size; if (const auto *S = dyn_cast<SharedSymbol>(this)) - return S->getSize<ELFT>(); + return S->Size; return 0; } -OutputSection *SymbolBody::getOutputSection() const { - if (auto *S = dyn_cast<DefinedRegular>(this)) { - if (S->Section) - return S->Section->getOutputSection(); +OutputSection *Symbol::getOutputSection() const { + if (auto *S = dyn_cast<Defined>(this)) { + if (auto *Sec = S->Section) + return Sec->Repl->getOutputSection(); return nullptr; } if (auto *S = dyn_cast<SharedSymbol>(this)) { - if (S->NeedsCopy) + if (S->CopyRelSec) return S->CopyRelSec->getParent(); return nullptr; } - if (isa<DefinedCommon>(this)) { - if (Config->DefineCommon) - return InX::Common->getParent(); - return nullptr; - } - return nullptr; } // If a symbol name contains '@', the characters after that is // a symbol version name. This function parses that. -void SymbolBody::parseSymbolVersion() { +void Symbol::parseSymbolVersion() { StringRef S = getName(); size_t Pos = S.find('@'); if (Pos == 0 || Pos == StringRef::npos) @@ -244,7 +189,7 @@ void SymbolBody::parseSymbolVersion() { Name = {S.data(), Pos}; // If this is not in this DSO, it is not a definition. - if (!isInCurrentDSO()) + if (!isDefined()) return; // '@@' in a symbol name means the default version. @@ -258,9 +203,9 @@ void SymbolBody::parseSymbolVersion() { continue; if (IsDefault) - symbol()->VersionId = Ver.Id; + VersionId = Ver.Id; else - symbol()->VersionId = Ver.Id | VERSYM_HIDDEN; + VersionId = Ver.Id | VERSYM_HIDDEN; return; } @@ -273,81 +218,34 @@ void SymbolBody::parseSymbolVersion() { Verstr); } -Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, - uint8_t Type) - : SymbolBody(K, Name, IsLocal, StOther, Type) {} - -template <class ELFT> bool DefinedRegular::isMipsPIC() const { - typedef typename ELFT::Ehdr Elf_Ehdr; - if (!Section || !isFunc()) - return false; - - auto *Sec = cast<InputSectionBase>(Section); - const Elf_Ehdr *Hdr = Sec->template getFile<ELFT>()->getObj().getHeader(); - return (this->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC || - (Hdr->e_flags & EF_MIPS_PIC); -} - -Undefined::Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, - uint8_t Type, InputFile *File) - : SymbolBody(SymbolBody::UndefinedKind, Name, IsLocal, StOther, Type) { - this->File = File; -} - -DefinedCommon::DefinedCommon(StringRef Name, uint64_t Size, uint32_t Alignment, - uint8_t StOther, uint8_t Type, InputFile *File) - : Defined(SymbolBody::DefinedCommonKind, Name, /*IsLocal=*/false, StOther, - Type), - Alignment(Alignment), Size(Size) { - this->File = File; -} - -// If a shared symbol is referred via a copy relocation, its alignment -// becomes part of the ABI. This function returns a symbol alignment. -// Because symbols don't have alignment attributes, we need to infer that. -template <class ELFT> uint32_t SharedSymbol::getAlignment() const { - auto *File = cast<SharedFile<ELFT>>(this->File); - uint32_t SecAlign = File->getSection(getSym<ELFT>())->sh_addralign; - uint64_t SymValue = getSym<ELFT>().st_value; - uint32_t SymAlign = uint32_t(1) << countTrailingZeros(SymValue); - return std::min(SecAlign, SymAlign); -} - InputFile *Lazy::fetch() { if (auto *S = dyn_cast<LazyArchive>(this)) return S->fetch(); return cast<LazyObject>(this)->fetch(); } -LazyArchive::LazyArchive(ArchiveFile &File, - const llvm::object::Archive::Symbol S, uint8_t Type) - : Lazy(LazyArchiveKind, S.getName(), Type), Sym(S) { - this->File = &File; -} - -LazyObject::LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type) - : Lazy(LazyObjectKind, Name, Type) { - this->File = &File; -} +ArchiveFile *LazyArchive::getFile() { return cast<ArchiveFile>(File); } InputFile *LazyArchive::fetch() { - std::pair<MemoryBufferRef, uint64_t> MBInfo = file()->getMember(&Sym); + std::pair<MemoryBufferRef, uint64_t> MBInfo = getFile()->getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. if (MBInfo.first.getBuffer().empty()) return nullptr; - return createObjectFile(MBInfo.first, file()->getName(), MBInfo.second); + return createObjectFile(MBInfo.first, getFile()->getName(), MBInfo.second); } -InputFile *LazyObject::fetch() { return file()->fetch(); } +LazyObjFile *LazyObject::getFile() { return cast<LazyObjFile>(File); } + +InputFile *LazyObject::fetch() { return getFile()->fetch(); } uint8_t Symbol::computeBinding() const { if (Config->Relocatable) return Binding; if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) return STB_LOCAL; - if (VersionId == VER_NDX_LOCAL && body()->isInCurrentDSO()) + if (VersionId == VER_NDX_LOCAL && isDefined()) return STB_LOCAL; if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE) return STB_GLOBAL; @@ -355,45 +253,36 @@ uint8_t Symbol::computeBinding() const { } bool Symbol::includeInDynsym() const { + if (!Config->HasDynSymTab) + return false; if (computeBinding() == STB_LOCAL) return false; - return ExportDynamic || body()->isShared() || - (body()->isUndefined() && Config->Shared); + if (!isDefined()) + return true; + return ExportDynamic; } // Print out a log message for --trace-symbol. void elf::printTraceSymbol(Symbol *Sym) { - SymbolBody *B = Sym->body(); std::string S; - if (B->isUndefined()) + if (Sym->isUndefined()) S = ": reference to "; - else if (B->isCommon()) + else if (Sym->isLazy()) + S = ": lazy definition of "; + else if (Sym->isShared()) + S = ": shared definition of "; + else if (dyn_cast_or_null<BssSection>(cast<Defined>(Sym)->Section)) S = ": common definition of "; else S = ": definition of "; - message(toString(B->File) + S + B->getName()); + message(toString(Sym->File) + S + Sym->getName()); } // Returns a symbol for an error message. -std::string lld::toString(const SymbolBody &B) { +std::string lld::toString(const Symbol &B) { if (Config->Demangle) - if (Optional<std::string> S = demangle(B.getName())) + if (Optional<std::string> S = demangleItanium(B.getName())) return *S; return B.getName(); } - -template uint32_t SymbolBody::template getSize<ELF32LE>() const; -template uint32_t SymbolBody::template getSize<ELF32BE>() const; -template uint64_t SymbolBody::template getSize<ELF64LE>() const; -template uint64_t SymbolBody::template getSize<ELF64BE>() const; - -template bool DefinedRegular::template isMipsPIC<ELF32LE>() const; -template bool DefinedRegular::template isMipsPIC<ELF32BE>() const; -template bool DefinedRegular::template isMipsPIC<ELF64LE>() const; -template bool DefinedRegular::template isMipsPIC<ELF64BE>() const; - -template uint32_t SharedSymbol::template getAlignment<ELF32LE>() const; -template uint32_t SharedSymbol::template getAlignment<ELF32BE>() const; -template uint32_t SharedSymbol::template getAlignment<ELF64LE>() const; -template uint32_t SharedSymbol::template getAlignment<ELF64BE>() const; diff --git a/ELF/Symbols.h b/ELF/Symbols.h index a1b3a6fba911..f4bb245f955d 100644 --- a/ELF/Symbols.h +++ b/ELF/Symbols.h @@ -18,7 +18,7 @@ #include "InputSection.h" #include "Strings.h" -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" @@ -27,53 +27,86 @@ namespace elf { class ArchiveFile; class BitcodeFile; +class BssSection; class InputFile; -class LazyObjectFile; -template <class ELFT> class ObjectFile; +class LazyObjFile; +template <class ELFT> class ObjFile; class OutputSection; template <class ELFT> class SharedFile; -struct Symbol; - // The base class for real symbol classes. -class SymbolBody { +class Symbol { public: enum Kind { - DefinedFirst, - DefinedRegularKind = DefinedFirst, + DefinedKind, SharedKind, - DefinedCommonKind, - DefinedLast = DefinedCommonKind, UndefinedKind, LazyArchiveKind, LazyObjectKind, }; - SymbolBody(Kind K) : SymbolKind(K) {} + Kind kind() const { return static_cast<Kind>(SymbolKind); } - Symbol *symbol(); - const Symbol *symbol() const { - return const_cast<SymbolBody *>(this)->symbol(); - } + // Symbol binding. This is not overwritten by replaceSymbol to track + // changes during resolution. In particular: + // - An undefined weak is still weak when it resolves to a shared library. + // - An undefined weak will not fetch archive members, but we have to + // remember it is weak. + uint8_t Binding; - Kind kind() const { return static_cast<Kind>(SymbolKind); } + // Version definition index. + uint16_t VersionId; + + // Symbol visibility. This is the computed minimum visibility of all + // observed non-DSO symbols. + unsigned Visibility : 2; + + // True if the symbol was used for linking and thus need to be added to the + // output file's symbol table. This is true for all symbols except for + // unreferenced DSO symbols and bitcode symbols that are unreferenced except + // by other bitcode objects. + unsigned IsUsedInRegularObj : 1; + + // If this flag is true and the symbol has protected or default visibility, it + // will appear in .dynsym. This flag is set by interposable DSO symbols in + // executables, by most symbols in DSOs and executables built with + // --export-dynamic, and by dynamic lists. + unsigned ExportDynamic : 1; + + // False if LTO shouldn't inline whatever this symbol points to. If a symbol + // is overwritten after LTO, LTO shouldn't inline the symbol because it + // doesn't know the final contents of the symbol. + unsigned CanInline : 1; + + // True if this symbol is specified by --trace-symbol option. + unsigned Traced : 1; + + // This symbol version was found in a version script. + unsigned InVersionScript : 1; + + // The file from which this symbol was created. + InputFile *File; + + bool includeInDynsym() const; + uint8_t computeBinding() const; + bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; } bool isUndefined() const { return SymbolKind == UndefinedKind; } - bool isDefined() const { return SymbolKind <= DefinedLast; } - bool isCommon() const { return SymbolKind == DefinedCommonKind; } + bool isDefined() const { return SymbolKind == DefinedKind; } + bool isShared() const { return SymbolKind == SharedKind; } + bool isLocal() const { return Binding == llvm::ELF::STB_LOCAL; } + bool isLazy() const { return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind; } - bool isShared() const { return SymbolKind == SharedKind; } - bool isInCurrentDSO() const { - return !isUndefined() && !isShared() && !isLazy(); - } - bool isLocal() const { return IsLocal; } - bool isPreemptible() const; + + // True is this is an undefined weak symbol. This only works once + // all input files have been added. + bool isUndefWeak() const; + StringRef getName() const { return Name; } uint8_t getVisibility() const { return StOther & 0x3; } void parseSymbolVersion(); - void copy(SymbolBody *Other); bool isInGot() const { return GotIndex != -1U; } bool isInPlt() const { return PltIndex != -1U; } @@ -85,12 +118,9 @@ public: uint64_t getGotPltOffset() const; uint64_t getGotPltVA() const; uint64_t getPltVA() const; - template <class ELFT> typename ELFT::uint getSize() const; + uint64_t getSize() const; OutputSection *getOutputSection() const; - // The file from which this symbol was created. - InputFile *File = nullptr; - uint32_t DynsymIndex = 0; uint32_t GotIndex = -1; uint32_t GotPltIndex = -1; @@ -98,23 +128,19 @@ public: uint32_t GlobalDynIndex = -1; protected: - SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, - uint8_t Type); + Symbol(Kind K, InputFile *File, StringRefZ Name, uint8_t Binding, + uint8_t StOther, uint8_t Type) + : Binding(Binding), File(File), SymbolKind(K), NeedsPltAddr(false), + IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), + IsInIgot(false), IsPreemptible(false), Used(!Config->GcSections), + Type(Type), StOther(StOther), Name(Name) {} const unsigned SymbolKind : 8; public: - // True if the linker has to generate a copy relocation. - // For SharedSymbol only. - unsigned NeedsCopy : 1; - // True the symbol should point to its PLT entry. // For SharedSymbol only. unsigned NeedsPltAddr : 1; - - // True if this is a local symbol. - unsigned IsLocal : 1; - // True if this symbol has an entry in the global part of MIPS GOT. unsigned IsInGlobalMipsGot : 1; @@ -127,6 +153,11 @@ public: // True if this symbol is in the Igot sub-section of the .got.plt or .got. unsigned IsInIgot : 1; + unsigned IsPreemptible : 1; + + // True if an undefined or shared symbol is used from a live section. + unsigned Used : 1; + // The following fields have the same meaning as the ELF symbol attributes. uint8_t Type; // symbol type uint8_t StOther; // st_other field value @@ -149,139 +180,111 @@ protected: StringRefZ Name; }; -// The base class for any defined symbols. -class Defined : public SymbolBody { -public: - Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type); - static bool classof(const SymbolBody *S) { return S->isDefined(); } -}; - -class DefinedCommon : public Defined { -public: - DefinedCommon(StringRef N, uint64_t Size, uint32_t Alignment, uint8_t StOther, - uint8_t Type, InputFile *File); - - static bool classof(const SymbolBody *S) { - return S->kind() == SymbolBody::DefinedCommonKind; - } - - // The output offset of this common symbol in the output bss. Computed by the - // writer. - uint64_t Offset; - - // The maximum alignment we have seen for this symbol. - uint32_t Alignment; - - uint64_t Size; -}; - -// Regular defined symbols read from object file symbol tables. -class DefinedRegular : public Defined { +// Represents a symbol that is defined in the current output file. +class Defined : public Symbol { public: - DefinedRegular(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type, - uint64_t Value, uint64_t Size, SectionBase *Section, - InputFile *File) - : Defined(SymbolBody::DefinedRegularKind, Name, IsLocal, StOther, Type), - Value(Value), Size(Size), Section(Section) { - this->File = File; - } - - // Return true if the symbol is a PIC function. - template <class ELFT> bool isMipsPIC() const; + Defined(InputFile *File, StringRefZ Name, uint8_t Binding, uint8_t StOther, + uint8_t Type, uint64_t Value, uint64_t Size, SectionBase *Section) + : Symbol(DefinedKind, File, Name, Binding, StOther, Type), Value(Value), + Size(Size), Section(Section) {} - static bool classof(const SymbolBody *S) { - return S->kind() == SymbolBody::DefinedRegularKind; - } + static bool classof(const Symbol *S) { return S->isDefined(); } uint64_t Value; uint64_t Size; SectionBase *Section; }; -class Undefined : public SymbolBody { +class Undefined : public Symbol { public: - Undefined(StringRefZ Name, bool IsLocal, uint8_t StOther, uint8_t Type, - InputFile *F); + Undefined(InputFile *File, StringRefZ Name, uint8_t Binding, uint8_t StOther, + uint8_t Type) + : Symbol(UndefinedKind, File, Name, Binding, StOther, Type) {} - static bool classof(const SymbolBody *S) { - return S->kind() == UndefinedKind; - } + static bool classof(const Symbol *S) { return S->kind() == UndefinedKind; } }; -class SharedSymbol : public Defined { +class SharedSymbol : public Symbol { public: - static bool classof(const SymbolBody *S) { - return S->kind() == SymbolBody::SharedKind; - } - - SharedSymbol(InputFile *File, StringRef Name, uint8_t StOther, uint8_t Type, - const void *ElfSym, const void *Verdef) - : Defined(SymbolBody::SharedKind, Name, /*IsLocal=*/false, StOther, Type), - Verdef(Verdef), ElfSym(ElfSym) { - // IFuncs defined in DSOs are treated as functions by the static linker. - if (isGnuIFunc()) + static bool classof(const Symbol *S) { return S->kind() == SharedKind; } + + SharedSymbol(InputFile *File, StringRef Name, uint8_t Binding, + uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, + uint32_t Alignment, uint32_t VerdefIndex) + : Symbol(SharedKind, File, Name, Binding, StOther, Type), Value(Value), + Size(Size), VerdefIndex(VerdefIndex), Alignment(Alignment) { + // GNU ifunc is a mechanism to allow user-supplied functions to + // resolve PLT slot values at load-time. This is contrary to the + // regualr symbol resolution scheme in which symbols are resolved just + // by name. Using this hook, you can program how symbols are solved + // for you program. For example, you can make "memcpy" to be resolved + // to a SSE-enabled version of memcpy only when a machine running the + // program supports the SSE instruction set. + // + // Naturally, such symbols should always be called through their PLT + // slots. What GNU ifunc symbols point to are resolver functions, and + // calling them directly doesn't make sense (unless you are writing a + // loader). + // + // For DSO symbols, we always call them through PLT slots anyway. + // So there's no difference between GNU ifunc and regular function + // symbols if they are in DSOs. So we can handle GNU_IFUNC as FUNC. + if (this->Type == llvm::ELF::STT_GNU_IFUNC) this->Type = llvm::ELF::STT_FUNC; - this->File = File; } - template <class ELFT> uint64_t getShndx() const { - return getSym<ELFT>().st_shndx; + template <class ELFT> SharedFile<ELFT> *getFile() const { + return cast<SharedFile<ELFT>>(File); } - template <class ELFT> uint64_t getValue() const { - return getSym<ELFT>().st_value; - } - - template <class ELFT> uint64_t getSize() const { - return getSym<ELFT>().st_size; - } - - template <class ELFT> uint32_t getAlignment() const; + // If not null, there is a copy relocation to this section. + InputSection *CopyRelSec = nullptr; - // This field is a pointer to the symbol's version definition. - const void *Verdef; + uint64_t Value; // st_value + uint64_t Size; // st_size - // CopyRelSec and CopyRelSecOff are significant only when NeedsCopy is true. - InputSection *CopyRelSec; - uint64_t CopyRelSecOff; + // This field is a index to the symbol's version definition. + uint32_t VerdefIndex; -private: - template <class ELFT> const typename ELFT::Sym &getSym() const { - return *(const typename ELFT::Sym *)ElfSym; - } - - const void *ElfSym; + uint32_t Alignment; }; -// This class represents a symbol defined in an archive file. It is -// created from an archive file header, and it knows how to load an -// object file from an archive to replace itself with a defined -// symbol. If the resolver finds both Undefined and Lazy for -// the same name, it will ask the Lazy to load a file. -class Lazy : public SymbolBody { +// This represents a symbol that is not yet in the link, but we know where to +// find it if needed. If the resolver finds both Undefined and Lazy for the same +// name, it will ask the Lazy to load a file. +// +// A special complication is the handling of weak undefined symbols. They should +// not load a file, but we have to remember we have seen both the weak undefined +// and the lazy. We represent that with a lazy symbol with a weak binding. This +// means that code looking for undefined symbols normally also has to take lazy +// symbols into consideration. +class Lazy : public Symbol { public: - static bool classof(const SymbolBody *S) { return S->isLazy(); } + static bool classof(const Symbol *S) { return S->isLazy(); } // Returns an object file for this symbol, or a nullptr if the file // was already returned. InputFile *fetch(); protected: - Lazy(SymbolBody::Kind K, StringRef Name, uint8_t Type) - : SymbolBody(K, Name, /*IsLocal=*/false, llvm::ELF::STV_DEFAULT, Type) {} + Lazy(Kind K, InputFile *File, StringRef Name, uint8_t Type) + : Symbol(K, File, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT, + Type) {} }; -// LazyArchive symbols represents symbols in archive files. +// This class represents a symbol defined in an archive file. It is +// created from an archive file header, and it knows how to load an +// object file from an archive to replace itself with a defined +// symbol. class LazyArchive : public Lazy { public: - LazyArchive(ArchiveFile &File, const llvm::object::Archive::Symbol S, - uint8_t Type); + LazyArchive(InputFile *File, const llvm::object::Archive::Symbol S, + uint8_t Type) + : Lazy(LazyArchiveKind, File, S.getName(), Type), Sym(S) {} - static bool classof(const SymbolBody *S) { - return S->kind() == LazyArchiveKind; - } + static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; } - ArchiveFile *file() { return (ArchiveFile *)this->File; } + ArchiveFile *getFile(); InputFile *fetch(); private: @@ -292,123 +295,85 @@ private: // --start-lib and --end-lib options. class LazyObject : public Lazy { public: - LazyObject(StringRef Name, LazyObjectFile &File, uint8_t Type); + LazyObject(InputFile *File, StringRef Name, uint8_t Type) + : Lazy(LazyObjectKind, File, Name, Type) {} - static bool classof(const SymbolBody *S) { - return S->kind() == LazyObjectKind; - } + static bool classof(const Symbol *S) { return S->kind() == LazyObjectKind; } - LazyObjectFile *file() { return (LazyObjectFile *)this->File; } + LazyObjFile *getFile(); InputFile *fetch(); }; // Some linker-generated symbols need to be created as -// DefinedRegular symbols. +// Defined symbols. struct ElfSym { // __bss_start - static DefinedRegular *Bss; + static Defined *Bss; // etext and _etext - static DefinedRegular *Etext1; - static DefinedRegular *Etext2; + static Defined *Etext1; + static Defined *Etext2; // edata and _edata - static DefinedRegular *Edata1; - static DefinedRegular *Edata2; + static Defined *Edata1; + static Defined *Edata2; // end and _end - static DefinedRegular *End1; - static DefinedRegular *End2; + static Defined *End1; + static Defined *End2; // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to // be at some offset from the base of the .got section, usually 0 or // the end of the .got. - static DefinedRegular *GlobalOffsetTable; + static Defined *GlobalOffsetTable; // _gp, _gp_disp and __gnu_local_gp symbols. Only for MIPS. - static DefinedRegular *MipsGp; - static DefinedRegular *MipsGpDisp; - static DefinedRegular *MipsLocalGp; + static Defined *MipsGp; + static Defined *MipsGpDisp; + static Defined *MipsLocalGp; }; -// A real symbol object, SymbolBody, is usually stored within a Symbol. There's -// always one Symbol for each symbol name. The resolver updates the SymbolBody -// stored in the Body field of this object as it resolves symbols. Symbol also -// holds computed properties of symbol names. -struct Symbol { - // Symbol binding. This is on the Symbol to track changes during resolution. - // In particular: - // An undefined weak is still weak when it resolves to a shared library. - // An undefined weak will not fetch archive members, but we have to remember - // it is weak. - uint8_t Binding; - - // Version definition index. - uint16_t VersionId; - - // Symbol visibility. This is the computed minimum visibility of all - // observed non-DSO symbols. - unsigned Visibility : 2; - - // True if the symbol was used for linking and thus need to be added to the - // output file's symbol table. This is true for all symbols except for - // unreferenced DSO symbols and bitcode symbols that are unreferenced except - // by other bitcode objects. - unsigned IsUsedInRegularObj : 1; - - // If this flag is true and the symbol has protected or default visibility, it - // will appear in .dynsym. This flag is set by interposable DSO symbols in - // executables, by most symbols in DSOs and executables built with - // --export-dynamic, and by dynamic lists. - unsigned ExportDynamic : 1; - - // True if this symbol is specified by --trace-symbol option. - unsigned Traced : 1; - - // This symbol version was found in a version script. - unsigned InVersionScript : 1; - - bool includeInDynsym() const; - uint8_t computeBinding() const; - bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; } - - // This field is used to store the Symbol's SymbolBody. This instantiation of - // AlignedCharArrayUnion gives us a struct with a char array field that is - // large and aligned enough to store any derived class of SymbolBody. - llvm::AlignedCharArrayUnion<DefinedCommon, DefinedRegular, Undefined, - SharedSymbol, LazyArchive, LazyObject> - Body; - - SymbolBody *body() { return reinterpret_cast<SymbolBody *>(Body.buffer); } - const SymbolBody *body() const { return const_cast<Symbol *>(this)->body(); } +// A buffer class that is large enough to hold any Symbol-derived +// object. We allocate memory using this class and instantiate a symbol +// using the placement new. +union SymbolUnion { + alignas(Defined) char A[sizeof(Defined)]; + alignas(Undefined) char C[sizeof(Undefined)]; + alignas(SharedSymbol) char D[sizeof(SharedSymbol)]; + alignas(LazyArchive) char E[sizeof(LazyArchive)]; + alignas(LazyObject) char F[sizeof(LazyObject)]; }; void printTraceSymbol(Symbol *Sym); template <typename T, typename... ArgT> -void replaceBody(Symbol *S, ArgT &&... Arg) { - static_assert(sizeof(T) <= sizeof(S->Body), "Body too small"); - static_assert(alignof(T) <= alignof(decltype(S->Body)), - "Body not aligned enough"); - assert(static_cast<SymbolBody *>(static_cast<T *>(nullptr)) == nullptr && - "Not a SymbolBody"); +void replaceSymbol(Symbol *S, ArgT &&... Arg) { + static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small"); + static_assert(alignof(T) <= alignof(SymbolUnion), + "SymbolUnion not aligned enough"); + assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr && + "Not a Symbol"); + + Symbol Sym = *S; - new (S->Body.buffer) T(std::forward<ArgT>(Arg)...); + new (S) T(std::forward<ArgT>(Arg)...); + + S->VersionId = Sym.VersionId; + S->Visibility = Sym.Visibility; + S->IsUsedInRegularObj = Sym.IsUsedInRegularObj; + S->ExportDynamic = Sym.ExportDynamic; + S->CanInline = Sym.CanInline; + S->Traced = Sym.Traced; + S->InVersionScript = Sym.InVersionScript; // Print out a log message if --trace-symbol was specified. // This is for debugging. if (S->Traced) printTraceSymbol(S); } - -inline Symbol *SymbolBody::symbol() { - assert(!isLocal()); - return reinterpret_cast<Symbol *>(reinterpret_cast<char *>(this) - - offsetof(Symbol, Body)); -} } // namespace elf -std::string toString(const elf::SymbolBody &B); +std::string toString(const elf::Symbol &B); } // namespace lld #endif diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index a67b039ddf21..b408e653dfa0 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -15,28 +15,32 @@ //===----------------------------------------------------------------------===// #include "SyntheticSections.h" +#include "Bits.h" #include "Config.h" -#include "Error.h" #include "InputFiles.h" #include "LinkerScript.h" -#include "Memory.h" #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" +#include "Symbols.h" #include "Target.h" -#include "Threads.h" #include "Writer.h" -#include "lld/Config/Version.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" +#include "lld/Common/Threads.h" +#include "lld/Common/Version.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/Object/Decompressor.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/MD5.h" #include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/SHA1.h" #include "llvm/Support/xxhash.h" #include <cstdlib> +#include <thread> using namespace llvm; using namespace llvm::dwarf; @@ -48,41 +52,18 @@ using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; +constexpr size_t MergeNoTailSection::NumShards; + +static void write32(void *Buf, uint32_t Val) { + endian::write32(Buf, Val, Config->Endianness); +} + uint64_t SyntheticSection::getVA() const { if (OutputSection *Sec = getParent()) return Sec->Addr + OutSecOff; return 0; } -template <class ELFT> static std::vector<DefinedCommon *> getCommonSymbols() { - std::vector<DefinedCommon *> V; - for (Symbol *S : Symtab<ELFT>::X->getSymbols()) - if (auto *B = dyn_cast<DefinedCommon>(S->body())) - V.push_back(B); - return V; -} - -// Find all common symbols and allocate space for them. -template <class ELFT> InputSection *elf::createCommonSection() { - if (!Config->DefineCommon) - return nullptr; - - // Sort the common symbols by alignment as an heuristic to pack them better. - std::vector<DefinedCommon *> Syms = getCommonSymbols<ELFT>(); - if (Syms.empty()) - return nullptr; - - std::stable_sort(Syms.begin(), Syms.end(), - [](const DefinedCommon *A, const DefinedCommon *B) { - return A->Alignment > B->Alignment; - }); - - BssSection *Sec = make<BssSection>("COMMON"); - for (DefinedCommon *Sym : Syms) - Sym->Offset = Sec->reserveSpace(Sym->Size, Sym->Alignment); - return Sec; -} - // Returns an LLD version string. static ArrayRef<uint8_t> getVersion() { // Check LLD_VERSION first for ease of testing. @@ -108,9 +89,8 @@ template <class ELFT> MergeInputSection *elf::createCommentSection() { Hdr.sh_addralign = 1; auto *Ret = - make<MergeInputSection>((ObjectFile<ELFT> *)nullptr, &Hdr, ".comment"); + make<MergeInputSection>((ObjFile<ELFT> *)nullptr, &Hdr, ".comment"); Ret->Data = getVersion(); - Ret->splitIntoPieces(); return Ret; } @@ -137,7 +117,7 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() { Sec->Live = false; Create = true; - std::string Filename = toString(Sec->getFile<ELFT>()); + std::string Filename = toString(Sec->File); const size_t Size = Sec->Data.size(); // Older version of BFD (such as the default FreeBSD linker) concatenate // .MIPS.abiflags instead of merging. To allow for this case (or potential @@ -154,7 +134,7 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() { return nullptr; } - // LLD checks ISA compatibility in getMipsEFlags(). Here we just + // LLD checks ISA compatibility in calcMipsEFlags(). Here we just // select the highest number of ISA/Rev/Ext. Flags.isa_level = std::max(Flags.isa_level, S->isa_level); Flags.isa_rev = std::max(Flags.isa_rev, S->isa_rev); @@ -197,16 +177,19 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() { if (!ELFT::Is64Bits) return nullptr; - Elf_Mips_RegInfo Reginfo = {}; - bool Create = false; + std::vector<InputSectionBase *> Sections; + for (InputSectionBase *Sec : InputSections) + if (Sec->Type == SHT_MIPS_OPTIONS) + Sections.push_back(Sec); - for (InputSectionBase *Sec : InputSections) { - if (Sec->Type != SHT_MIPS_OPTIONS) - continue; + if (Sections.empty()) + return nullptr; + + Elf_Mips_RegInfo Reginfo = {}; + for (InputSectionBase *Sec : Sections) { Sec->Live = false; - Create = true; - std::string Filename = toString(Sec->getFile<ELFT>()); + std::string Filename = toString(Sec->File); ArrayRef<uint8_t> D = Sec->Data; while (!D.empty()) { @@ -230,9 +213,7 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() { } }; - if (Create) - return make<MipsOptionsSection<ELFT>>(Reginfo); - return nullptr; + return make<MipsOptionsSection<ELFT>>(Reginfo); } // MIPS .reginfo section. @@ -255,32 +236,31 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() { if (ELFT::Is64Bits) return nullptr; - Elf_Mips_RegInfo Reginfo = {}; - bool Create = false; + std::vector<InputSectionBase *> Sections; + for (InputSectionBase *Sec : InputSections) + if (Sec->Type == SHT_MIPS_REGINFO) + Sections.push_back(Sec); - for (InputSectionBase *Sec : InputSections) { - if (Sec->Type != SHT_MIPS_REGINFO) - continue; + if (Sections.empty()) + return nullptr; + + Elf_Mips_RegInfo Reginfo = {}; + for (InputSectionBase *Sec : Sections) { Sec->Live = false; - Create = true; if (Sec->Data.size() != sizeof(Elf_Mips_RegInfo)) { - error(toString(Sec->getFile<ELFT>()) + - ": invalid size of .reginfo section"); + error(toString(Sec->File) + ": invalid size of .reginfo section"); return nullptr; } auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data()); if (Config->Relocatable && R->ri_gp_value) - error(toString(Sec->getFile<ELFT>()) + - ": unsupported non-zero ri_gp_value"); + error(toString(Sec->File) + ": unsupported non-zero ri_gp_value"); Reginfo.ri_gprmask |= R->ri_gprmask; Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value; }; - if (Create) - return make<MipsReginfoSection<ELFT>>(Reginfo); - return nullptr; + return make<MipsReginfoSection<ELFT>>(Reginfo); } InputSection *elf::createInterpSection() { @@ -294,10 +274,10 @@ InputSection *elf::createInterpSection() { return Sec; } -SymbolBody *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, - uint64_t Size, InputSectionBase *Section) { - auto *S = make<DefinedRegular>(Name, /*IsLocal*/ true, STV_DEFAULT, Type, - Value, Size, Section, nullptr); +Symbol *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, + uint64_t Size, InputSectionBase *Section) { + auto *S = make<Defined>(Section->File, Name, STB_LOCAL, STV_DEFAULT, Type, + Value, Size, Section); if (InX::SymTab) InX::SymTab->addSymbol(S); return S; @@ -320,14 +300,13 @@ static size_t getHashSize() { } BuildIdSection::BuildIdSection() - : SyntheticSection(SHF_ALLOC, SHT_NOTE, 1, ".note.gnu.build-id"), + : SyntheticSection(SHF_ALLOC, SHT_NOTE, 4, ".note.gnu.build-id"), HashSize(getHashSize()) {} void BuildIdSection::writeTo(uint8_t *Buf) { - endianness E = Config->Endianness; - write32(Buf, 4, E); // Name size - write32(Buf + 4, HashSize, E); // Content size - write32(Buf + 8, NT_GNU_BUILD_ID, E); // Type + write32(Buf, 4); // Name size + write32(Buf + 4, HashSize); // Content size + write32(Buf + 8, NT_GNU_BUILD_ID); // Type memcpy(Buf + 12, "GNU", 4); // Name string HashBuf = Buf + 16; } @@ -364,15 +343,12 @@ void BuildIdSection::computeHash( HashFn(HashBuf, Hashes); } -BssSection::BssSection(StringRef Name) - : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, 0, Name) {} - -size_t BssSection::reserveSpace(uint64_t Size, uint32_t Alignment) { +BssSection::BssSection(StringRef Name, uint64_t Size, uint32_t Alignment) + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, Alignment, Name) { + this->Bss = true; if (OutputSection *Sec = getParent()) - Sec->updateAlignment(Alignment); - this->Size = alignTo(this->Size, Alignment) + Size; - this->Alignment = std::max(this->Alignment, Alignment); - return this->Size - Size; + Sec->Alignment = std::max(Sec->Alignment, Alignment); + this->Size = Size; } void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) { @@ -393,8 +369,8 @@ void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) { }); break; case BuildIdKind::Uuid: - if (getRandomBytes(HashBuf, HashSize)) - error("entropy source failure"); + if (auto EC = getRandomBytes(HashBuf, HashSize)) + error("entropy source failure: " + EC.message()); break; case BuildIdKind::Hexstring: memcpy(HashBuf, Config->BuildIdVector.data(), Config->BuildIdVector.size()); @@ -404,101 +380,99 @@ void BuildIdSection::writeBuildId(ArrayRef<uint8_t> Buf) { } } -template <class ELFT> -EhFrameSection<ELFT>::EhFrameSection() +EhFrameSection::EhFrameSection() : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame") {} // Search for an existing CIE record or create a new one. // CIE records from input object files are uniquified by their contents // and where their relocations point to. -template <class ELFT> -template <class RelTy> -CieRecord *EhFrameSection<ELFT>::addCie(EhSectionPiece &Piece, - ArrayRef<RelTy> Rels) { - auto *Sec = cast<EhInputSection>(Piece.ID); - const endianness E = ELFT::TargetEndianness; - if (read32<E>(Piece.data().data() + 4) != 0) +template <class ELFT, class RelTy> +CieRecord *EhFrameSection::addCie(EhSectionPiece &Cie, ArrayRef<RelTy> Rels) { + auto *Sec = cast<EhInputSection>(Cie.Sec); + if (read32(Cie.data().data() + 4, Config->Endianness) != 0) fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame"); - SymbolBody *Personality = nullptr; - unsigned FirstRelI = Piece.FirstRelocation; + Symbol *Personality = nullptr; + unsigned FirstRelI = Cie.FirstRelocation; if (FirstRelI != (unsigned)-1) Personality = &Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]); // Search for an existing CIE by CIE contents/relocation target pair. - CieRecord *&Cie = CieMap[{Piece.data(), Personality}]; + CieRecord *&Rec = CieMap[{Cie.data(), Personality}]; // If not found, create a new one. - if (!Cie) { - Cie = make<CieRecord>(); - Cie->Piece = &Piece; - Cies.push_back(Cie); + if (!Rec) { + Rec = make<CieRecord>(); + Rec->Cie = &Cie; + CieRecords.push_back(Rec); } - return Cie; + return Rec; } // There is one FDE per function. Returns true if a given FDE // points to a live function. -template <class ELFT> -template <class RelTy> -bool EhFrameSection<ELFT>::isFdeLive(EhSectionPiece &Piece, - ArrayRef<RelTy> Rels) { - auto *Sec = cast<EhInputSection>(Piece.ID); - unsigned FirstRelI = Piece.FirstRelocation; +template <class ELFT, class RelTy> +bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) { + auto *Sec = cast<EhInputSection>(Fde.Sec); + unsigned FirstRelI = Fde.FirstRelocation; + + // An FDE should point to some function because FDEs are to describe + // functions. That's however not always the case due to an issue of + // ld.gold with -r. ld.gold may discard only functions and leave their + // corresponding FDEs, which results in creating bad .eh_frame sections. + // To deal with that, we ignore such FDEs. if (FirstRelI == (unsigned)-1) return false; + const RelTy &Rel = Rels[FirstRelI]; - SymbolBody &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel); - auto *D = dyn_cast<DefinedRegular>(&B); - if (!D || !D->Section) - return false; - auto *Target = - cast<InputSectionBase>(cast<InputSectionBase>(D->Section)->Repl); - return Target && Target->Live; + Symbol &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel); + + // FDEs for garbage-collected or merged-by-ICF sections are dead. + if (auto *D = dyn_cast<Defined>(&B)) + if (SectionBase *Sec = D->Section) + return Sec->Live; + return false; } // .eh_frame is a sequence of CIE or FDE records. In general, there // is one CIE record per input object file which is followed by // a list of FDEs. This function searches an existing CIE or create a new // one and associates FDEs to the CIE. -template <class ELFT> -template <class RelTy> -void EhFrameSection<ELFT>::addSectionAux(EhInputSection *Sec, - ArrayRef<RelTy> Rels) { - const endianness E = ELFT::TargetEndianness; - +template <class ELFT, class RelTy> +void EhFrameSection::addSectionAux(EhInputSection *Sec, ArrayRef<RelTy> Rels) { DenseMap<size_t, CieRecord *> OffsetToCie; for (EhSectionPiece &Piece : Sec->Pieces) { // The empty record is the end marker. - if (Piece.size() == 4) + if (Piece.Size == 4) return; size_t Offset = Piece.InputOff; - uint32_t ID = read32<E>(Piece.data().data() + 4); + uint32_t ID = read32(Piece.data().data() + 4, Config->Endianness); if (ID == 0) { - OffsetToCie[Offset] = addCie(Piece, Rels); + OffsetToCie[Offset] = addCie<ELFT>(Piece, Rels); continue; } uint32_t CieOffset = Offset + 4 - ID; - CieRecord *Cie = OffsetToCie[CieOffset]; - if (!Cie) + CieRecord *Rec = OffsetToCie[CieOffset]; + if (!Rec) fatal(toString(Sec) + ": invalid CIE reference"); - if (!isFdeLive(Piece, Rels)) + if (!isFdeLive<ELFT>(Piece, Rels)) continue; - Cie->FdePieces.push_back(&Piece); + Rec->Fdes.push_back(&Piece); NumFdes++; } } -template <class ELFT> -void EhFrameSection<ELFT>::addSection(InputSectionBase *C) { +template <class ELFT> void EhFrameSection::addSection(InputSectionBase *C) { auto *Sec = cast<EhInputSection>(C); Sec->Parent = this; - updateAlignment(Sec->Alignment); + + Alignment = std::max(Alignment, Sec->Alignment); Sections.push_back(Sec); + for (auto *DS : Sec->DependentSections) DependentSections.push_back(DS); @@ -509,42 +483,36 @@ void EhFrameSection<ELFT>::addSection(InputSectionBase *C) { if (Sec->Pieces.empty()) return; - if (Sec->NumRelocations) { - if (Sec->AreRelocsRela) - addSectionAux(Sec, Sec->template relas<ELFT>()); - else - addSectionAux(Sec, Sec->template rels<ELFT>()); - return; - } - addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr)); + if (Sec->AreRelocsRela) + addSectionAux<ELFT>(Sec, Sec->template relas<ELFT>()); + else + addSectionAux<ELFT>(Sec, Sec->template rels<ELFT>()); } -template <class ELFT> static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) { memcpy(Buf, D.data(), D.size()); - size_t Aligned = alignTo(D.size(), sizeof(typename ELFT::uint)); + size_t Aligned = alignTo(D.size(), Config->Wordsize); // Zero-clear trailing padding if it exists. memset(Buf + D.size(), 0, Aligned - D.size()); // Fix the size field. -4 since size does not include the size field itself. - const endianness E = ELFT::TargetEndianness; - write32<E>(Buf, Aligned - 4); + write32(Buf, Aligned - 4); } -template <class ELFT> void EhFrameSection<ELFT>::finalizeContents() { +void EhFrameSection::finalizeContents() { if (this->Size) return; // Already finalized. size_t Off = 0; - for (CieRecord *Cie : Cies) { - Cie->Piece->OutputOff = Off; - Off += alignTo(Cie->Piece->size(), Config->Wordsize); + for (CieRecord *Rec : CieRecords) { + Rec->Cie->OutputOff = Off; + Off += alignTo(Rec->Cie->Size, Config->Wordsize); - for (EhSectionPiece *Fde : Cie->FdePieces) { + for (EhSectionPiece *Fde : Rec->Fdes) { Fde->OutputOff = Off; - Off += alignTo(Fde->size(), Config->Wordsize); + Off += alignTo(Fde->Size, Config->Wordsize); } } @@ -557,32 +525,46 @@ template <class ELFT> void EhFrameSection<ELFT>::finalizeContents() { this->Size = Off; } -template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) { - const endianness E = ELFT::TargetEndianness; +// Returns data for .eh_frame_hdr. .eh_frame_hdr is a binary search table +// to get an FDE from an address to which FDE is applied. This function +// returns a list of such pairs. +std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const { + uint8_t *Buf = getParent()->Loc + OutSecOff; + std::vector<FdeData> Ret; + + for (CieRecord *Rec : CieRecords) { + uint8_t Enc = getFdeEncoding(Rec->Cie); + for (EhSectionPiece *Fde : Rec->Fdes) { + uint32_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); + uint32_t FdeVA = getParent()->Addr + Fde->OutputOff; + Ret.push_back({Pc, FdeVA}); + } + } + return Ret; +} + +static uint64_t readFdeAddr(uint8_t *Buf, int Size) { switch (Size) { case DW_EH_PE_udata2: - return read16<E>(Buf); + return read16(Buf, Config->Endianness); case DW_EH_PE_udata4: - return read32<E>(Buf); + return read32(Buf, Config->Endianness); case DW_EH_PE_udata8: - return read64<E>(Buf); + return read64(Buf, Config->Endianness); case DW_EH_PE_absptr: - if (ELFT::Is64Bits) - return read64<E>(Buf); - return read32<E>(Buf); + return readUint(Buf); } fatal("unknown FDE size encoding"); } // Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to. // We need it to create .eh_frame_hdr section. -template <class ELFT> -uint64_t EhFrameSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff, - uint8_t Enc) { +uint64_t EhFrameSection::getFdePc(uint8_t *Buf, size_t FdeOff, + uint8_t Enc) const { // The starting address to which this FDE applies is // stored at FDE + 8 byte. size_t Off = FdeOff + 8; - uint64_t Addr = readFdeAddr<ELFT>(Buf + Off, Enc & 0x7); + uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0x7); if ((Enc & 0x70) == DW_EH_PE_absptr) return Addr; if ((Enc & 0x70) == DW_EH_PE_pcrel) @@ -590,50 +572,39 @@ uint64_t EhFrameSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff, fatal("unknown FDE size relative encoding"); } -template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) { - const endianness E = ELFT::TargetEndianness; - for (CieRecord *Cie : Cies) { - size_t CieOffset = Cie->Piece->OutputOff; - writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data()); +void EhFrameSection::writeTo(uint8_t *Buf) { + // Write CIE and FDE records. + for (CieRecord *Rec : CieRecords) { + size_t CieOffset = Rec->Cie->OutputOff; + writeCieFde(Buf + CieOffset, Rec->Cie->data()); - for (EhSectionPiece *Fde : Cie->FdePieces) { + for (EhSectionPiece *Fde : Rec->Fdes) { size_t Off = Fde->OutputOff; - writeCieFde<ELFT>(Buf + Off, Fde->data()); + writeCieFde(Buf + Off, Fde->data()); // FDE's second word should have the offset to an associated CIE. // Write it. - write32<E>(Buf + Off + 4, Off + 4 - CieOffset); + write32(Buf + Off + 4, Off + 4 - CieOffset); } } + // Apply relocations. .eh_frame section contents are not contiguous + // in the output buffer, but relocateAlloc() still works because + // getOffset() takes care of discontiguous section pieces. for (EhInputSection *S : Sections) S->relocateAlloc(Buf, nullptr); - - // Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table - // to get a FDE from an address to which FDE is applied. So here - // we obtain two addresses and pass them to EhFrameHdr object. - if (In<ELFT>::EhFrameHdr) { - for (CieRecord *Cie : Cies) { - uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece); - for (SectionPiece *Fde : Cie->FdePieces) { - uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); - uint64_t FdeVA = getParent()->Addr + Fde->OutputOff; - In<ELFT>::EhFrameHdr->addFde(Pc, FdeVA); - } - } - } } GotSection::GotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotEntrySize, ".got") {} -void GotSection::addEntry(SymbolBody &Sym) { +void GotSection::addEntry(Symbol &Sym) { Sym.GotIndex = NumEntries; ++NumEntries; } -bool GotSection::addDynTlsEntry(SymbolBody &Sym) { +bool GotSection::addDynTlsEntry(Symbol &Sym) { if (Sym.GlobalDynIndex != -1U) return false; Sym.GlobalDynIndex = NumEntries; @@ -652,20 +623,21 @@ bool GotSection::addTlsIndex() { return true; } -uint64_t GotSection::getGlobalDynAddr(const SymbolBody &B) const { +uint64_t GotSection::getGlobalDynAddr(const Symbol &B) const { return this->getVA() + B.GlobalDynIndex * Config->Wordsize; } -uint64_t GotSection::getGlobalDynOffset(const SymbolBody &B) const { +uint64_t GotSection::getGlobalDynOffset(const Symbol &B) const { return B.GlobalDynIndex * Config->Wordsize; } void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; } bool GotSection::empty() const { - // If we have a relocation that is relative to GOT (such as GOTOFFREL), - // we need to emit a GOT even if it's empty. - return NumEntries == 0 && !HasGotOffRel; + // We need to emit a GOT even if it's empty if there's a relocation that is + // relative to GOT(such as GOTOFFREL) or there's a symbol that points to a GOT + // (i.e. _GLOBAL_OFFSET_TABLE_). + return NumEntries == 0 && !HasGotOffRel && !ElfSym::GlobalOffsetTable; } void GotSection::writeTo(uint8_t *Buf) { @@ -679,7 +651,7 @@ MipsGotSection::MipsGotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16, ".got") {} -void MipsGotSection::addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr) { +void MipsGotSection::addEntry(Symbol &Sym, int64_t Addend, RelExpr Expr) { // For "true" local symbols which can be referenced from the same module // only compiler creates two instructions for address loading: // @@ -721,7 +693,7 @@ void MipsGotSection::addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr) { TlsEntries.push_back(&Sym); return; } - auto AddEntry = [&](SymbolBody &S, uint64_t A, GotEntries &Items) { + auto AddEntry = [&](Symbol &S, uint64_t A, GotEntries &Items) { if (S.isInGot() && !A) return; size_t NewIndex = Items.size(); @@ -731,7 +703,7 @@ void MipsGotSection::addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr) { if (!A) S.GotIndex = NewIndex; }; - if (Sym.isPreemptible()) { + if (Sym.IsPreemptible) { // Ignore addends for preemptible symbols. They got single GOT entry anyway. AddEntry(Sym, 0, GlobalEntries); Sym.IsInGlobalMipsGot = true; @@ -746,7 +718,7 @@ void MipsGotSection::addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr) { } } -bool MipsGotSection::addDynTlsEntry(SymbolBody &Sym) { +bool MipsGotSection::addDynTlsEntry(Symbol &Sym) { if (Sym.GlobalDynIndex != -1U) return false; Sym.GlobalDynIndex = TlsEntries.size(); @@ -775,7 +747,7 @@ static uint64_t getMipsPageCount(uint64_t Size) { return (Size + 0xfffe) / 0xffff + 1; } -uint64_t MipsGotSection::getPageEntryOffset(const SymbolBody &B, +uint64_t MipsGotSection::getPageEntryOffset(const Symbol &B, int64_t Addend) const { const OutputSection *OutSec = B.getOutputSection(); uint64_t SecAddr = getMipsPageAddr(OutSec->Addr); @@ -785,8 +757,8 @@ uint64_t MipsGotSection::getPageEntryOffset(const SymbolBody &B, return (HeaderEntriesNum + Index) * Config->Wordsize; } -uint64_t MipsGotSection::getBodyEntryOffset(const SymbolBody &B, - int64_t Addend) const { +uint64_t MipsGotSection::getSymEntryOffset(const Symbol &B, + int64_t Addend) const { // Calculate offset of the GOT entries block: TLS, global, local. uint64_t Index = HeaderEntriesNum + PageEntriesNum; if (B.isTls()) @@ -810,11 +782,11 @@ uint64_t MipsGotSection::getTlsOffset() const { return (getLocalEntriesNum() + GlobalEntries.size()) * Config->Wordsize; } -uint64_t MipsGotSection::getGlobalDynOffset(const SymbolBody &B) const { +uint64_t MipsGotSection::getGlobalDynOffset(const Symbol &B) const { return B.GlobalDynIndex * Config->Wordsize; } -const SymbolBody *MipsGotSection::getFirstGlobalEntry() const { +const Symbol *MipsGotSection::getFirstGlobalEntry() const { return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first; } @@ -825,7 +797,7 @@ unsigned MipsGotSection::getLocalEntriesNum() const { void MipsGotSection::finalizeContents() { updateAllocSize(); } -void MipsGotSection::updateAllocSize() { +bool MipsGotSection::updateAllocSize() { PageEntriesNum = 0; for (std::pair<const OutputSection *, size_t> &P : PageIndexMap) { // For each output section referenced by GOT page relocations calculate @@ -839,6 +811,7 @@ void MipsGotSection::updateAllocSize() { } Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) * Config->Wordsize; + return false; } bool MipsGotSection::empty() const { @@ -849,19 +822,6 @@ bool MipsGotSection::empty() const { uint64_t MipsGotSection::getGp() const { return ElfSym::MipsGp->getVA(0); } -static uint64_t readUint(uint8_t *Buf) { - if (Config->Is64) - return read64(Buf, Config->Endianness); - return read32(Buf, Config->Endianness); -} - -static void writeUint(uint8_t *Buf, uint64_t Val) { - if (Config->Is64) - write64(Buf, Val, Config->Endianness); - else - write32(Buf, Val, Config->Endianness); -} - void MipsGotSection::writeTo(uint8_t *Buf) { // Set the MSB of the second GOT slot. This is not required by any // MIPS ABI documentation, though. @@ -892,8 +852,10 @@ void MipsGotSection::writeTo(uint8_t *Buf) { auto AddEntry = [&](const GotEntry &SA) { uint8_t *Entry = Buf; Buf += Config->Wordsize; - const SymbolBody *Body = SA.first; - uint64_t VA = Body->getVA(SA.second); + const Symbol *Sym = SA.first; + uint64_t VA = Sym->getVA(SA.second); + if (Sym->StOther & STO_MIPS_MICROMIPS) + VA |= 1; writeUint(Entry, VA); }; std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry); @@ -906,8 +868,8 @@ void MipsGotSection::writeTo(uint8_t *Buf) { // https://www.linux-mips.org/wiki/NPTL if (TlsIndexOff != -1U && !Config->Pic) writeUint(Buf + TlsIndexOff, 1); - for (const SymbolBody *B : TlsEntries) { - if (!B || B->isPreemptible()) + for (const Symbol *B : TlsEntries) { + if (!B || B->IsPreemptible) continue; uint64_t VA = B->getVA(); if (B->GotIndex != -1U) { @@ -927,7 +889,7 @@ GotPltSection::GotPltSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Target->GotPltEntrySize, ".got.plt") {} -void GotPltSection::addEntry(SymbolBody &Sym) { +void GotPltSection::addEntry(Symbol &Sym) { Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size(); Entries.push_back(&Sym); } @@ -940,7 +902,7 @@ size_t GotPltSection::getSize() const { void GotPltSection::writeTo(uint8_t *Buf) { Target->writeGotPltHeader(Buf); Buf += Target->GotPltHeaderEntriesNum * Target->GotPltEntrySize; - for (const SymbolBody *B : Entries) { + for (const Symbol *B : Entries) { Target->writeGotPlt(Buf, *B); Buf += Config->Wordsize; } @@ -953,7 +915,7 @@ IgotPltSection::IgotPltSection() Target->GotPltEntrySize, Config->EMachine == EM_ARM ? ".got" : ".got.plt") {} -void IgotPltSection::addEntry(SymbolBody &Sym) { +void IgotPltSection::addEntry(Symbol &Sym) { Sym.IsInIgot = true; Sym.GotPltIndex = Entries.size(); Entries.push_back(&Sym); @@ -964,7 +926,7 @@ size_t IgotPltSection::getSize() const { } void IgotPltSection::writeTo(uint8_t *Buf) { - for (const SymbolBody *B : Entries) { + for (const Symbol *B : Entries) { Target->writeIgotPlt(Buf, *B); Buf += Config->Wordsize; } @@ -996,6 +958,7 @@ unsigned StringTableSection::addString(StringRef S, bool HashIt) { void StringTableSection::writeTo(uint8_t *Buf) { for (StringRef S : Strings) { memcpy(Buf, S.data(), S.size()); + Buf[S.size()] = '\0'; Buf += S.size() + 1; } } @@ -1018,26 +981,61 @@ DynamicSection<ELFT>::DynamicSection() if (Config->EMachine == EM_MIPS || Config->ZRodynamic) this->Flags = SHF_ALLOC; - addEntries(); -} - -// There are some dynamic entries that don't depend on other sections. -// Such entries can be set early. -template <class ELFT> void DynamicSection<ELFT>::addEntries() { // Add strings to .dynstr early so that .dynstr's size will be // fixed early. for (StringRef S : Config->FilterList) - add({DT_FILTER, InX::DynStrTab->addString(S)}); + addInt(DT_FILTER, InX::DynStrTab->addString(S)); for (StringRef S : Config->AuxiliaryList) - add({DT_AUXILIARY, InX::DynStrTab->addString(S)}); + addInt(DT_AUXILIARY, InX::DynStrTab->addString(S)); + if (!Config->Rpath.empty()) - add({Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, - InX::DynStrTab->addString(Config->Rpath)}); - for (SharedFile<ELFT> *F : Symtab<ELFT>::X->getSharedFiles()) - if (F->isNeeded()) - add({DT_NEEDED, InX::DynStrTab->addString(F->SoName)}); + addInt(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, + InX::DynStrTab->addString(Config->Rpath)); + + for (InputFile *File : SharedFiles) { + SharedFile<ELFT> *F = cast<SharedFile<ELFT>>(File); + if (F->IsNeeded) + addInt(DT_NEEDED, InX::DynStrTab->addString(F->SoName)); + } if (!Config->SoName.empty()) - add({DT_SONAME, InX::DynStrTab->addString(Config->SoName)}); + addInt(DT_SONAME, InX::DynStrTab->addString(Config->SoName)); +} + +template <class ELFT> +void DynamicSection<ELFT>::add(int32_t Tag, std::function<uint64_t()> Fn) { + Entries.push_back({Tag, Fn}); +} + +template <class ELFT> +void DynamicSection<ELFT>::addInt(int32_t Tag, uint64_t Val) { + Entries.push_back({Tag, [=] { return Val; }}); +} + +template <class ELFT> +void DynamicSection<ELFT>::addInSec(int32_t Tag, InputSection *Sec) { + Entries.push_back( + {Tag, [=] { return Sec->getParent()->Addr + Sec->OutSecOff; }}); +} + +template <class ELFT> +void DynamicSection<ELFT>::addOutSec(int32_t Tag, OutputSection *Sec) { + Entries.push_back({Tag, [=] { return Sec->Addr; }}); +} + +template <class ELFT> +void DynamicSection<ELFT>::addSize(int32_t Tag, OutputSection *Sec) { + Entries.push_back({Tag, [=] { return Sec->Size; }}); +} + +template <class ELFT> +void DynamicSection<ELFT>::addSym(int32_t Tag, Symbol *Sym) { + Entries.push_back({Tag, [=] { return Sym->getVA(); }}); +} + +// Add remaining entries to complete .dynamic contents. +template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { + if (this->Size) + return; // Already finalized. // Set DT_FLAGS and DT_FLAGS_1. uint32_t DtFlags = 0; @@ -1058,9 +1056,9 @@ template <class ELFT> void DynamicSection<ELFT>::addEntries() { } if (DtFlags) - add({DT_FLAGS, DtFlags}); + addInt(DT_FLAGS, DtFlags); if (DtFlags1) - add({DT_FLAGS_1, DtFlags1}); + addInt(DT_FLAGS_1, DtFlags1); // DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We // need it for each process, so we don't write it for DSOs. The loader writes @@ -1071,133 +1069,115 @@ template <class ELFT> void DynamicSection<ELFT>::addEntries() { // debugger this information. Such systems may choose make .dynamic read-only. // If the target is such a system (used -z rodynamic) don't write DT_DEBUG. if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic) - add({DT_DEBUG, (uint64_t)0}); -} - -// Add remaining entries to complete .dynamic contents. -template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { - if (this->Size) - return; // Already finalized. + addInt(DT_DEBUG, 0); this->Link = InX::DynStrTab->getParent()->SectionIndex; - if (In<ELFT>::RelaDyn->getParent() && !In<ELFT>::RelaDyn->empty()) { + if (InX::RelaDyn->getParent() && !InX::RelaDyn->empty()) { + addInSec(InX::RelaDyn->DynamicTag, InX::RelaDyn); + addSize(InX::RelaDyn->SizeDynamicTag, InX::RelaDyn->getParent()); + bool IsRela = Config->IsRela; - add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn}); - add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent(), - Entry::SecSize}); - add({IsRela ? DT_RELAENT : DT_RELENT, - uint64_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); + addInt(IsRela ? DT_RELAENT : DT_RELENT, + IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel)); // MIPS dynamic loader does not support RELCOUNT tag. // The problem is in the tight relation between dynamic // relocations and GOT. So do not emit this tag on MIPS. if (Config->EMachine != EM_MIPS) { - size_t NumRelativeRels = In<ELFT>::RelaDyn->getRelativeRelocCount(); + size_t NumRelativeRels = InX::RelaDyn->getRelativeRelocCount(); if (Config->ZCombreloc && NumRelativeRels) - add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels}); + addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels); } } - if (In<ELFT>::RelaPlt->getParent() && !In<ELFT>::RelaPlt->empty()) { - add({DT_JMPREL, In<ELFT>::RelaPlt}); - add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent(), Entry::SecSize}); + if (InX::RelaPlt->getParent() && !InX::RelaPlt->empty()) { + addInSec(DT_JMPREL, InX::RelaPlt); + addSize(DT_PLTRELSZ, InX::RelaPlt->getParent()); switch (Config->EMachine) { case EM_MIPS: - add({DT_MIPS_PLTGOT, In<ELFT>::GotPlt}); + addInSec(DT_MIPS_PLTGOT, InX::GotPlt); break; case EM_SPARCV9: - add({DT_PLTGOT, In<ELFT>::Plt}); + addInSec(DT_PLTGOT, InX::Plt); break; default: - add({DT_PLTGOT, In<ELFT>::GotPlt}); + addInSec(DT_PLTGOT, InX::GotPlt); break; } - add({DT_PLTREL, uint64_t(Config->IsRela ? DT_RELA : DT_REL)}); + addInt(DT_PLTREL, Config->IsRela ? DT_RELA : DT_REL); } - add({DT_SYMTAB, InX::DynSymTab}); - add({DT_SYMENT, sizeof(Elf_Sym)}); - add({DT_STRTAB, InX::DynStrTab}); - add({DT_STRSZ, InX::DynStrTab->getSize()}); + addInSec(DT_SYMTAB, InX::DynSymTab); + addInt(DT_SYMENT, sizeof(Elf_Sym)); + addInSec(DT_STRTAB, InX::DynStrTab); + addInt(DT_STRSZ, InX::DynStrTab->getSize()); if (!Config->ZText) - add({DT_TEXTREL, (uint64_t)0}); + addInt(DT_TEXTREL, 0); if (InX::GnuHashTab) - add({DT_GNU_HASH, InX::GnuHashTab}); - if (In<ELFT>::HashTab) - add({DT_HASH, In<ELFT>::HashTab}); + addInSec(DT_GNU_HASH, InX::GnuHashTab); + if (InX::HashTab) + addInSec(DT_HASH, InX::HashTab); if (Out::PreinitArray) { - add({DT_PREINIT_ARRAY, Out::PreinitArray}); - add({DT_PREINIT_ARRAYSZ, Out::PreinitArray, Entry::SecSize}); + addOutSec(DT_PREINIT_ARRAY, Out::PreinitArray); + addSize(DT_PREINIT_ARRAYSZ, Out::PreinitArray); } if (Out::InitArray) { - add({DT_INIT_ARRAY, Out::InitArray}); - add({DT_INIT_ARRAYSZ, Out::InitArray, Entry::SecSize}); + addOutSec(DT_INIT_ARRAY, Out::InitArray); + addSize(DT_INIT_ARRAYSZ, Out::InitArray); } if (Out::FiniArray) { - add({DT_FINI_ARRAY, Out::FiniArray}); - add({DT_FINI_ARRAYSZ, Out::FiniArray, Entry::SecSize}); + addOutSec(DT_FINI_ARRAY, Out::FiniArray); + addSize(DT_FINI_ARRAYSZ, Out::FiniArray); } - if (SymbolBody *B = Symtab<ELFT>::X->findInCurrentDSO(Config->Init)) - add({DT_INIT, B}); - if (SymbolBody *B = Symtab<ELFT>::X->findInCurrentDSO(Config->Fini)) - add({DT_FINI, B}); + if (Symbol *B = Symtab->find(Config->Init)) + if (B->isDefined()) + addSym(DT_INIT, B); + if (Symbol *B = Symtab->find(Config->Fini)) + if (B->isDefined()) + addSym(DT_FINI, B); bool HasVerNeed = In<ELFT>::VerNeed->getNeedNum() != 0; if (HasVerNeed || In<ELFT>::VerDef) - add({DT_VERSYM, In<ELFT>::VerSym}); + addInSec(DT_VERSYM, In<ELFT>::VerSym); if (In<ELFT>::VerDef) { - add({DT_VERDEF, In<ELFT>::VerDef}); - add({DT_VERDEFNUM, getVerDefNum()}); + addInSec(DT_VERDEF, In<ELFT>::VerDef); + addInt(DT_VERDEFNUM, getVerDefNum()); } if (HasVerNeed) { - add({DT_VERNEED, In<ELFT>::VerNeed}); - add({DT_VERNEEDNUM, In<ELFT>::VerNeed->getNeedNum()}); + addInSec(DT_VERNEED, In<ELFT>::VerNeed); + addInt(DT_VERNEEDNUM, In<ELFT>::VerNeed->getNeedNum()); } if (Config->EMachine == EM_MIPS) { - add({DT_MIPS_RLD_VERSION, 1}); - add({DT_MIPS_FLAGS, RHF_NOTPOT}); - add({DT_MIPS_BASE_ADDRESS, Config->ImageBase}); - add({DT_MIPS_SYMTABNO, InX::DynSymTab->getNumSymbols()}); - add({DT_MIPS_LOCAL_GOTNO, InX::MipsGot->getLocalEntriesNum()}); - if (const SymbolBody *B = InX::MipsGot->getFirstGlobalEntry()) - add({DT_MIPS_GOTSYM, B->DynsymIndex}); + addInt(DT_MIPS_RLD_VERSION, 1); + addInt(DT_MIPS_FLAGS, RHF_NOTPOT); + addInt(DT_MIPS_BASE_ADDRESS, Target->getImageBase()); + addInt(DT_MIPS_SYMTABNO, InX::DynSymTab->getNumSymbols()); + + add(DT_MIPS_LOCAL_GOTNO, [] { return InX::MipsGot->getLocalEntriesNum(); }); + + if (const Symbol *B = InX::MipsGot->getFirstGlobalEntry()) + addInt(DT_MIPS_GOTSYM, B->DynsymIndex); else - add({DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols()}); - add({DT_PLTGOT, InX::MipsGot}); + addInt(DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols()); + addInSec(DT_PLTGOT, InX::MipsGot); if (InX::MipsRldMap) - add({DT_MIPS_RLD_MAP, InX::MipsRldMap}); + addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap); } - getParent()->Link = this->Link; + addInt(DT_NULL, 0); - // +1 for DT_NULL - this->Size = (Entries.size() + 1) * this->Entsize; + getParent()->Link = this->Link; + this->Size = Entries.size() * this->Entsize; } template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { auto *P = reinterpret_cast<Elf_Dyn *>(Buf); - for (const Entry &E : Entries) { - P->d_tag = E.Tag; - switch (E.Kind) { - case Entry::SecAddr: - P->d_un.d_ptr = E.OutSec->Addr; - break; - case Entry::InSecAddr: - P->d_un.d_ptr = E.InSec->getParent()->Addr + E.InSec->OutSecOff; - break; - case Entry::SecSize: - P->d_un.d_val = E.OutSec->Size; - break; - case Entry::SymAddr: - P->d_un.d_ptr = E.Sym->getVA(); - break; - case Entry::PlainInt: - P->d_un.d_val = E.Val; - break; - } + for (std::pair<int32_t, std::function<uint64_t()>> &KV : Entries) { + P->d_tag = KV.first; + P->d_un.d_val = KV.second(); ++P; } } @@ -1218,21 +1198,57 @@ uint32_t DynamicReloc::getSymIndex() const { return 0; } -template <class ELFT> -RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort) - : SyntheticSection(SHF_ALLOC, Config->IsRela ? SHT_RELA : SHT_REL, - Config->Wordsize, Name), - Sort(Sort) { - this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); -} +RelocationBaseSection::RelocationBaseSection(StringRef Name, uint32_t Type, + int32_t DynamicTag, + int32_t SizeDynamicTag) + : SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name), + DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {} -template <class ELFT> -void RelocationSection<ELFT>::addReloc(const DynamicReloc &Reloc) { +void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) { if (Reloc.Type == Target->RelativeRel) ++NumRelativeRelocs; Relocs.push_back(Reloc); } +void RelocationBaseSection::finalizeContents() { + // If all relocations are R_*_RELATIVE they don't refer to any + // dynamic symbol and we don't need a dynamic symbol table. If that + // is the case, just use 0 as the link. + Link = InX::DynSymTab ? InX::DynSymTab->getParent()->SectionIndex : 0; + + // Set required output section properties. + getParent()->Link = Link; +} + +template <class ELFT> +static void encodeDynamicReloc(typename ELFT::Rela *P, + const DynamicReloc &Rel) { + if (Config->IsRela) + P->r_addend = Rel.getAddend(); + P->r_offset = Rel.getOffset(); + if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot) + // The MIPS GOT section contains dynamic relocations that correspond to TLS + // entries. These entries are placed after the global and local sections of + // the GOT. At the point when we create these relocations, the size of the + // global and local sections is unknown, so the offset that we store in the + // TLS entry's DynamicReloc is relative to the start of the TLS section of + // the GOT, rather than being relative to the start of the GOT. This line of + // code adds the size of the global and local sections to the virtual + // address computed by getOffset() in order to adjust it into the TLS + // section. + P->r_offset += InX::MipsGot->getTlsOffset(); + P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL); +} + +template <class ELFT> +RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort) + : RelocationBaseSection(Name, Config->IsRela ? SHT_RELA : SHT_REL, + Config->IsRela ? DT_RELA : DT_REL, + Config->IsRela ? DT_RELASZ : DT_RELSZ), + Sort(Sort) { + this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); +} + template <class ELFT, class RelTy> static bool compRelocations(const RelTy &A, const RelTy &B) { bool AIsRel = A.getType(Config->IsMips64EL) == Target->RelativeRel; @@ -1246,18 +1262,8 @@ static bool compRelocations(const RelTy &A, const RelTy &B) { template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) { uint8_t *BufBegin = Buf; for (const DynamicReloc &Rel : Relocs) { - auto *P = reinterpret_cast<Elf_Rela *>(Buf); + encodeDynamicReloc<ELFT>(reinterpret_cast<Elf_Rela *>(Buf), Rel); Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); - - if (Config->IsRela) - P->r_addend = Rel.getAddend(); - P->r_offset = Rel.getOffset(); - if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot) - // Dynamic relocation against MIPS GOT section make deal TLS entries - // allocated in the end of the GOT. We need to adjust the offset to take - // in account 'local' and 'global' GOT entries. - P->r_offset += InX::MipsGot->getTlsOffset(); - P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL); } if (Sort) { @@ -1275,12 +1281,192 @@ template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() { return this->Entsize * Relocs.size(); } -template <class ELFT> void RelocationSection<ELFT>::finalizeContents() { - this->Link = InX::DynSymTab ? InX::DynSymTab->getParent()->SectionIndex - : InX::SymTab->getParent()->SectionIndex; +template <class ELFT> +AndroidPackedRelocationSection<ELFT>::AndroidPackedRelocationSection( + StringRef Name) + : RelocationBaseSection( + Name, Config->IsRela ? SHT_ANDROID_RELA : SHT_ANDROID_REL, + Config->IsRela ? DT_ANDROID_RELA : DT_ANDROID_REL, + Config->IsRela ? DT_ANDROID_RELASZ : DT_ANDROID_RELSZ) { + this->Entsize = 1; +} - // Set required output section properties. - getParent()->Link = this->Link; +template <class ELFT> +bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() { + // This function computes the contents of an Android-format packed relocation + // section. + // + // This format compresses relocations by using relocation groups to factor out + // fields that are common between relocations and storing deltas from previous + // relocations in SLEB128 format (which has a short representation for small + // numbers). A good example of a relocation type with common fields is + // R_*_RELATIVE, which is normally used to represent function pointers in + // vtables. In the REL format, each relative relocation has the same r_info + // field, and is only different from other relative relocations in terms of + // the r_offset field. By sorting relocations by offset, grouping them by + // r_info and representing each relocation with only the delta from the + // previous offset, each 8-byte relocation can be compressed to as little as 1 + // byte (or less with run-length encoding). This relocation packer was able to + // reduce the size of the relocation section in an Android Chromium DSO from + // 2,911,184 bytes to 174,693 bytes, or 6% of the original size. + // + // A relocation section consists of a header containing the literal bytes + // 'APS2' followed by a sequence of SLEB128-encoded integers. The first two + // elements are the total number of relocations in the section and an initial + // r_offset value. The remaining elements define a sequence of relocation + // groups. Each relocation group starts with a header consisting of the + // following elements: + // + // - the number of relocations in the relocation group + // - flags for the relocation group + // - (if RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG is set) the r_offset delta + // for each relocation in the group. + // - (if RELOCATION_GROUPED_BY_INFO_FLAG is set) the value of the r_info + // field for each relocation in the group. + // - (if RELOCATION_GROUP_HAS_ADDEND_FLAG and + // RELOCATION_GROUPED_BY_ADDEND_FLAG are set) the r_addend delta for + // each relocation in the group. + // + // Following the relocation group header are descriptions of each of the + // relocations in the group. They consist of the following elements: + // + // - (if RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG is not set) the r_offset + // delta for this relocation. + // - (if RELOCATION_GROUPED_BY_INFO_FLAG is not set) the value of the r_info + // field for this relocation. + // - (if RELOCATION_GROUP_HAS_ADDEND_FLAG is set and + // RELOCATION_GROUPED_BY_ADDEND_FLAG is not set) the r_addend delta for + // this relocation. + + size_t OldSize = RelocData.size(); + + RelocData = {'A', 'P', 'S', '2'}; + raw_svector_ostream OS(RelocData); + auto Add = [&](int64_t V) { encodeSLEB128(V, OS); }; + + // The format header includes the number of relocations and the initial + // offset (we set this to zero because the first relocation group will + // perform the initial adjustment). + Add(Relocs.size()); + Add(0); + + std::vector<Elf_Rela> Relatives, NonRelatives; + + for (const DynamicReloc &Rel : Relocs) { + Elf_Rela R; + encodeDynamicReloc<ELFT>(&R, Rel); + + if (R.getType(Config->IsMips64EL) == Target->RelativeRel) + Relatives.push_back(R); + else + NonRelatives.push_back(R); + } + + std::sort(Relatives.begin(), Relatives.end(), + [](const Elf_Rel &A, const Elf_Rel &B) { + return A.r_offset < B.r_offset; + }); + + // Try to find groups of relative relocations which are spaced one word + // apart from one another. These generally correspond to vtable entries. The + // format allows these groups to be encoded using a sort of run-length + // encoding, but each group will cost 7 bytes in addition to the offset from + // the previous group, so it is only profitable to do this for groups of + // size 8 or larger. + std::vector<Elf_Rela> UngroupedRelatives; + std::vector<std::vector<Elf_Rela>> RelativeGroups; + for (auto I = Relatives.begin(), E = Relatives.end(); I != E;) { + std::vector<Elf_Rela> Group; + do { + Group.push_back(*I++); + } while (I != E && (I - 1)->r_offset + Config->Wordsize == I->r_offset); + + if (Group.size() < 8) + UngroupedRelatives.insert(UngroupedRelatives.end(), Group.begin(), + Group.end()); + else + RelativeGroups.emplace_back(std::move(Group)); + } + + unsigned HasAddendIfRela = + Config->IsRela ? RELOCATION_GROUP_HAS_ADDEND_FLAG : 0; + + uint64_t Offset = 0; + uint64_t Addend = 0; + + // Emit the run-length encoding for the groups of adjacent relative + // relocations. Each group is represented using two groups in the packed + // format. The first is used to set the current offset to the start of the + // group (and also encodes the first relocation), and the second encodes the + // remaining relocations. + for (std::vector<Elf_Rela> &G : RelativeGroups) { + // The first relocation in the group. + Add(1); + Add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | + RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela); + Add(G[0].r_offset - Offset); + Add(Target->RelativeRel); + if (Config->IsRela) { + Add(G[0].r_addend - Addend); + Addend = G[0].r_addend; + } + + // The remaining relocations. + Add(G.size() - 1); + Add(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | + RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela); + Add(Config->Wordsize); + Add(Target->RelativeRel); + if (Config->IsRela) { + for (auto I = G.begin() + 1, E = G.end(); I != E; ++I) { + Add(I->r_addend - Addend); + Addend = I->r_addend; + } + } + + Offset = G.back().r_offset; + } + + // Now the ungrouped relatives. + if (!UngroupedRelatives.empty()) { + Add(UngroupedRelatives.size()); + Add(RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela); + Add(Target->RelativeRel); + for (Elf_Rela &R : UngroupedRelatives) { + Add(R.r_offset - Offset); + Offset = R.r_offset; + if (Config->IsRela) { + Add(R.r_addend - Addend); + Addend = R.r_addend; + } + } + } + + // Finally the non-relative relocations. + std::sort(NonRelatives.begin(), NonRelatives.end(), + [](const Elf_Rela &A, const Elf_Rela &B) { + return A.r_offset < B.r_offset; + }); + if (!NonRelatives.empty()) { + Add(NonRelatives.size()); + Add(HasAddendIfRela); + for (Elf_Rela &R : NonRelatives) { + Add(R.r_offset - Offset); + Offset = R.r_offset; + Add(R.r_info); + if (Config->IsRela) { + Add(R.r_addend - Addend); + Addend = R.r_addend; + } + } + } + + // Returns whether the section size changed. We need to keep recomputing both + // section layout and the contents of this section until the size converges + // because changing this section's size can affect section layout, which in + // turn can affect the sizes of the LEB-encoded integers stored in this + // section. + return RelocData.size() != OldSize; } SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec) @@ -1299,17 +1485,13 @@ static bool sortMipsSymbols(const SymbolTableEntry &L, const SymbolTableEntry &R) { // Sort entries related to non-local preemptible symbols by GOT indexes. // All other entries go to the first part of GOT in arbitrary order. - bool LIsInLocalGot = !L.Symbol->IsInGlobalMipsGot; - bool RIsInLocalGot = !R.Symbol->IsInGlobalMipsGot; + bool LIsInLocalGot = !L.Sym->IsInGlobalMipsGot; + bool RIsInLocalGot = !R.Sym->IsInGlobalMipsGot; if (LIsInLocalGot || RIsInLocalGot) return !RIsInLocalGot; - return L.Symbol->GotIndex < R.Symbol->GotIndex; + return L.Sym->GotIndex < R.Sym->GotIndex; } -// Finalize a symbol table. The ELF spec requires that all local -// symbols precede global symbols, so we sort symbol entries in this -// function. (For .dynsym, we don't do that because symbols for -// dynamic linking are inherently all globals.) void SymbolTableBaseSection::finalizeContents() { getParent()->Link = StrTabSec.getParent()->SectionIndex; @@ -1328,26 +1510,27 @@ void SymbolTableBaseSection::finalizeContents() { } size_t I = 0; - for (const SymbolTableEntry &S : Symbols) - S.Symbol->DynsymIndex = ++I; + for (const SymbolTableEntry &S : Symbols) S.Sym->DynsymIndex = ++I; return; } } +// The ELF spec requires that all local symbols precede global symbols, so we +// sort symbol entries in this function. (For .dynsym, we don't do that because +// symbols for dynamic linking are inherently all globals.) void SymbolTableBaseSection::postThunkContents() { if (this->Type == SHT_DYNSYM) return; // move all local symbols before global symbols. auto It = std::stable_partition( Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) { - return S.Symbol->isLocal() || - S.Symbol->symbol()->computeBinding() == STB_LOCAL; + return S.Sym->isLocal() || S.Sym->computeBinding() == STB_LOCAL; }); size_t NumLocals = It - Symbols.begin(); getParent()->Info = NumLocals + 1; } -void SymbolTableBaseSection::addSymbol(SymbolBody *B) { +void SymbolTableBaseSection::addSymbol(Symbol *B) { // Adding a local symbol to a .dynsym is a bug. assert(this->Type != SHT_DYNSYM || !B->isLocal()); @@ -1355,19 +1538,25 @@ void SymbolTableBaseSection::addSymbol(SymbolBody *B) { Symbols.push_back({B, StrTabSec.addString(B->getName(), HashIt)}); } -size_t SymbolTableBaseSection::getSymbolIndex(SymbolBody *Body) { - auto I = llvm::find_if(Symbols, [&](const SymbolTableEntry &E) { - if (E.Symbol == Body) - return true; - // This is used for -r, so we have to handle multiple section - // symbols being combined. - if (Body->Type == STT_SECTION && E.Symbol->Type == STT_SECTION) - return Body->getOutputSection() == E.Symbol->getOutputSection(); - return false; +size_t SymbolTableBaseSection::getSymbolIndex(Symbol *Sym) { + // Initializes symbol lookup tables lazily. This is used only + // for -r or -emit-relocs. + llvm::call_once(OnceFlag, [&] { + SymbolIndexMap.reserve(Symbols.size()); + size_t I = 0; + for (const SymbolTableEntry &E : Symbols) { + if (E.Sym->Type == STT_SECTION) + SectionIndexMap[E.Sym->getOutputSection()] = ++I; + else + SymbolIndexMap[E.Sym] = ++I; + } }); - if (I == Symbols.end()) - return 0; - return I - Symbols.begin() + 1; + + // Section symbols are mapped based on their output sections + // to maintain their semantics. + if (Sym->Type == STT_SECTION) + return SectionIndexMap.lookup(Sym->getOutputSection()); + return SymbolIndexMap.lookup(Sym); } template <class ELFT> @@ -1379,46 +1568,56 @@ SymbolTableSection<ELFT>::SymbolTableSection(StringTableSection &StrTabSec) // Write the internal symbol table contents to the output symbol table. template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { // The first entry is a null entry as per the ELF spec. + memset(Buf, 0, sizeof(Elf_Sym)); Buf += sizeof(Elf_Sym); auto *ESym = reinterpret_cast<Elf_Sym *>(Buf); for (SymbolTableEntry &Ent : Symbols) { - SymbolBody *Body = Ent.Symbol; + Symbol *Sym = Ent.Sym; // Set st_info and st_other. - if (Body->isLocal()) { - ESym->setBindingAndType(STB_LOCAL, Body->Type); + ESym->st_other = 0; + if (Sym->isLocal()) { + ESym->setBindingAndType(STB_LOCAL, Sym->Type); } else { - ESym->setBindingAndType(Body->symbol()->computeBinding(), Body->Type); - ESym->setVisibility(Body->symbol()->Visibility); + ESym->setBindingAndType(Sym->computeBinding(), Sym->Type); + ESym->setVisibility(Sym->Visibility); } ESym->st_name = Ent.StrTabOffset; // Set a section index. - if (const OutputSection *OutSec = Body->getOutputSection()) + BssSection *CommonSec = nullptr; + if (!Config->DefineCommon) + if (auto *D = dyn_cast<Defined>(Sym)) + CommonSec = dyn_cast_or_null<BssSection>(D->Section); + if (CommonSec) + ESym->st_shndx = SHN_COMMON; + else if (const OutputSection *OutSec = Sym->getOutputSection()) ESym->st_shndx = OutSec->SectionIndex; - else if (isa<DefinedRegular>(Body)) + else if (isa<Defined>(Sym)) ESym->st_shndx = SHN_ABS; - else if (isa<DefinedCommon>(Body)) - ESym->st_shndx = SHN_COMMON; + else + ESym->st_shndx = SHN_UNDEF; // Copy symbol size if it is a defined symbol. st_size is not significant // for undefined symbols, so whether copying it or not is up to us if that's // the case. We'll leave it as zero because by not setting a value, we can // get the exact same outputs for two sets of input files that differ only // in undefined symbol size in DSOs. - if (ESym->st_shndx != SHN_UNDEF) - ESym->st_size = Body->getSize<ELFT>(); + if (ESym->st_shndx == SHN_UNDEF) + ESym->st_size = 0; + else + ESym->st_size = Sym->getSize(); // st_value is usually an address of a symbol, but that has a // special meaining for uninstantiated common symbols (this can // occur if -r is given). - if (!Config->DefineCommon && isa<DefinedCommon>(Body)) - ESym->st_value = cast<DefinedCommon>(Body)->Alignment; + if (CommonSec) + ESym->st_value = CommonSec->Alignment; else - ESym->st_value = Body->getVA(); + ESym->st_value = Sym->getVA(); ++ESym; } @@ -1431,13 +1630,22 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { auto *ESym = reinterpret_cast<Elf_Sym *>(Buf); for (SymbolTableEntry &Ent : Symbols) { - SymbolBody *Body = Ent.Symbol; - if (Body->isInPlt() && Body->NeedsPltAddr) + Symbol *Sym = Ent.Sym; + if (Sym->isInPlt() && Sym->NeedsPltAddr) ESym->st_other |= STO_MIPS_PLT; - + if (isMicroMips()) { + // Set STO_MIPS_MICROMIPS flag and less-significant bit for + // defined microMIPS symbols and shared symbols with PLT record. + if ((Sym->isDefined() && (Sym->StOther & STO_MIPS_MICROMIPS)) || + (Sym->isShared() && Sym->NeedsPltAddr)) { + if (StrTabSec.isDynamic()) + ESym->st_value |= 1; + ESym->st_other |= STO_MIPS_MICROMIPS; + } + } if (Config->Relocatable) - if (auto *D = dyn_cast<DefinedRegular>(Body)) - if (D->isMipsPIC<ELFT>()) + if (auto *D = dyn_cast<Defined>(Sym)) + if (isMipsPIC<ELFT>(D)) ESym->st_other |= STO_MIPS_PIC; ++ESym; } @@ -1496,12 +1704,16 @@ void GnuHashTableSection::finalizeContents() { } void GnuHashTableSection::writeTo(uint8_t *Buf) { + // The output buffer is not guaranteed to be zero-cleared because we pre- + // fill executable sections with trap instructions. This is a precaution + // for that case, which happens only when -no-rosegment is given. + memset(Buf, 0, Size); + // Write a header. - write32(Buf, NBuckets, Config->Endianness); - write32(Buf + 4, InX::DynSymTab->getNumSymbols() - Symbols.size(), - Config->Endianness); - write32(Buf + 8, MaskWords, Config->Endianness); - write32(Buf + 12, getShift2(), Config->Endianness); + write32(Buf, NBuckets); + write32(Buf + 4, InX::DynSymTab->getNumSymbols() - Symbols.size()); + write32(Buf + 8, MaskWords); + write32(Buf + 12, getShift2()); Buf += 16; // Write a bloom filter and a hash table. @@ -1529,29 +1741,24 @@ void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) { } void GnuHashTableSection::writeHashTable(uint8_t *Buf) { - // Group symbols by hash value. - std::vector<std::vector<Entry>> Syms(NBuckets); - for (const Entry &Ent : Symbols) - Syms[Ent.Hash % NBuckets].push_back(Ent); - - // Write hash buckets. Hash buckets contain indices in the following - // hash value table. uint32_t *Buckets = reinterpret_cast<uint32_t *>(Buf); - for (size_t I = 0; I < NBuckets; ++I) - if (!Syms[I].empty()) - write32(Buckets + I, Syms[I][0].Body->DynsymIndex, Config->Endianness); - - // Write a hash value table. It represents a sequence of chains that - // share the same hash modulo value. The last element of each chain - // is terminated by LSB 1. + uint32_t OldBucket = -1; uint32_t *Values = Buckets + NBuckets; - size_t I = 0; - for (std::vector<Entry> &Vec : Syms) { - if (Vec.empty()) + for (auto I = Symbols.begin(), E = Symbols.end(); I != E; ++I) { + // Write a hash value. It represents a sequence of chains that share the + // same hash modulo value. The last element of each chain is terminated by + // LSB 1. + uint32_t Hash = I->Hash; + bool IsLastInChain = (I + 1) == E || I->BucketIdx != (I + 1)->BucketIdx; + Hash = IsLastInChain ? Hash | 1 : Hash & ~1; + write32(Values++, Hash); + + if (I->BucketIdx == OldBucket) continue; - for (const Entry &Ent : makeArrayRef(Vec).drop_back()) - write32(Values + I++, Ent.Hash & ~1, Config->Endianness); - write32(Values + I++, Vec.back().Hash | 1, Config->Endianness); + // Write a hash bucket. Hash buckets contain indices in the following hash + // value table. + write32(Buckets + I->BucketIdx, I->Sym->DynsymIndex); + OldBucket = I->BucketIdx; } } @@ -1562,22 +1769,6 @@ static uint32_t hashGnu(StringRef Name) { return H; } -// Returns a number of hash buckets to accomodate given number of elements. -// We want to choose a moderate number that is not too small (which -// causes too many hash collisions) and not too large (which wastes -// disk space.) -// -// We return a prime number because it (is believed to) achieve good -// hash distribution. -static size_t getBucketSize(size_t NumSymbols) { - // List of largest prime numbers that are not greater than 2^n + 1. - for (size_t N : {131071, 65521, 32749, 16381, 8191, 4093, 2039, 1021, 509, - 251, 127, 61, 31, 13, 7, 3, 1}) - if (N <= NumSymbols) - return N; - return 0; -} - // Add symbols to this symbol hash table. Note that this function // destructively sort a given vector -- which is needed because // GNU-style hash table places some sorting requirements. @@ -1586,66 +1777,70 @@ void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) { // its type correctly. std::vector<SymbolTableEntry>::iterator Mid = std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) { - return S.Symbol->isUndefined(); + // Shared symbols that this executable preempts are special. The dynamic + // linker has to look them up, so they have to be in the hash table. + if (auto *SS = dyn_cast<SharedSymbol>(S.Sym)) + return SS->CopyRelSec == nullptr && !SS->NeedsPltAddr; + return !S.Sym->isDefined(); }); if (Mid == V.end()) return; + // We chose load factor 4 for the on-disk hash table. For each hash + // collision, the dynamic linker will compare a uint32_t hash value. + // Since the integer comparison is quite fast, we believe we can make + // the load factor even larger. 4 is just a conservative choice. + NBuckets = std::max<size_t>((V.end() - Mid) / 4, 1); + for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) { - SymbolBody *B = Ent.Symbol; - Symbols.push_back({B, Ent.StrTabOffset, hashGnu(B->getName())}); + Symbol *B = Ent.Sym; + uint32_t Hash = hashGnu(B->getName()); + uint32_t BucketIdx = Hash % NBuckets; + Symbols.push_back({B, Ent.StrTabOffset, Hash, BucketIdx}); } - NBuckets = getBucketSize(Symbols.size()); - std::stable_sort(Symbols.begin(), Symbols.end(), - [&](const Entry &L, const Entry &R) { - return L.Hash % NBuckets < R.Hash % NBuckets; - }); + std::stable_sort( + Symbols.begin(), Symbols.end(), + [](const Entry &L, const Entry &R) { return L.BucketIdx < R.BucketIdx; }); V.erase(Mid, V.end()); for (const Entry &Ent : Symbols) - V.push_back({Ent.Body, Ent.StrTabOffset}); + V.push_back({Ent.Sym, Ent.StrTabOffset}); } -template <class ELFT> -HashTableSection<ELFT>::HashTableSection() +HashTableSection::HashTableSection() : SyntheticSection(SHF_ALLOC, SHT_HASH, 4, ".hash") { this->Entsize = 4; } -template <class ELFT> void HashTableSection<ELFT>::finalizeContents() { +void HashTableSection::finalizeContents() { getParent()->Link = InX::DynSymTab->getParent()->SectionIndex; unsigned NumEntries = 2; // nbucket and nchain. NumEntries += InX::DynSymTab->getNumSymbols(); // The chain entries. // Create as many buckets as there are symbols. - // FIXME: This is simplistic. We can try to optimize it, but implementing - // support for SHT_GNU_HASH is probably even more profitable. NumEntries += InX::DynSymTab->getNumSymbols(); this->Size = NumEntries * 4; } -template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) { - // A 32-bit integer type in the target endianness. - typedef typename ELFT::Word Elf_Word; - +void HashTableSection::writeTo(uint8_t *Buf) { unsigned NumSymbols = InX::DynSymTab->getNumSymbols(); - auto *P = reinterpret_cast<Elf_Word *>(Buf); - *P++ = NumSymbols; // nbucket - *P++ = NumSymbols; // nchain + uint32_t *P = reinterpret_cast<uint32_t *>(Buf); + write32(P++, NumSymbols); // nbucket + write32(P++, NumSymbols); // nchain - Elf_Word *Buckets = P; - Elf_Word *Chains = P + NumSymbols; + uint32_t *Buckets = P; + uint32_t *Chains = P + NumSymbols; for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) { - SymbolBody *Body = S.Symbol; - StringRef Name = Body->getName(); - unsigned I = Body->DynsymIndex; + Symbol *Sym = S.Sym; + StringRef Name = Sym->getName(); + unsigned I = Sym->DynsymIndex; uint32_t Hash = hashSysV(Name) % NumSymbols; Chains[I] = Buckets[Hash]; - Buckets[Hash] = I; + write32(Buckets + Hash, I); } } @@ -1668,7 +1863,7 @@ void PltSection::writeTo(uint8_t *Buf) { unsigned PltOff = getPltRelocOff(); for (auto &I : Entries) { - const SymbolBody *B = I.first; + const Symbol *B = I.first; unsigned RelOff = I.second + PltOff; uint64_t Got = B->getGotPltVA(); uint64_t Plt = this->getVA() + Off; @@ -1677,14 +1872,15 @@ void PltSection::writeTo(uint8_t *Buf) { } } -template <class ELFT> void PltSection::addEntry(SymbolBody &Sym) { +template <class ELFT> void PltSection::addEntry(Symbol &Sym) { Sym.PltIndex = Entries.size(); - RelocationSection<ELFT> *PltRelocSection = In<ELFT>::RelaPlt; + RelocationBaseSection *PltRelocSection = InX::RelaPlt; if (HeaderSize == 0) { - PltRelocSection = In<ELFT>::RelaIplt; + PltRelocSection = InX::RelaIplt; Sym.IsInIplt = true; } - unsigned RelOff = PltRelocSection->getRelocOffset(); + unsigned RelOff = + static_cast<RelocationSection<ELFT> *>(PltRelocSection)->getRelocOffset(); Entries.push_back(std::make_pair(&Sym, RelOff)); } @@ -1709,35 +1905,29 @@ unsigned PltSection::getPltRelocOff() const { return (HeaderSize == 0) ? InX::Plt->getSize() : 0; } -GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks) - : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"), - StringPool(llvm::StringTableBuilder::ELF), Chunks(std::move(Chunks)) {} - -// Iterative hash function for symbol's name is described in .gdb_index format -// specification. Note that we use one for version 5 to 7 here, it is different -// for version 4. -static uint32_t hash(StringRef Str) { - uint32_t R = 0; - for (uint8_t C : Str) - R = R * 67 + tolower(C) - 113; - return R; +// The string hash function for .gdb_index. +static uint32_t computeGdbHash(StringRef S) { + uint32_t H = 0; + for (uint8_t C : S) + H = H * 67 + tolower(C) - 113; + return H; } -static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf) { - std::vector<CompilationUnitEntry> Ret; - for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units()) - Ret.push_back({CU->getOffset(), CU->getLength() + 4}); +static std::vector<GdbIndexChunk::CuEntry> readCuList(DWARFContext &Dwarf) { + std::vector<GdbIndexChunk::CuEntry> Ret; + for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units()) + Ret.push_back({Cu->getOffset(), Cu->getLength() + 4}); return Ret; } -static std::vector<AddressEntry> readAddressArea(DWARFContext &Dwarf, - InputSection *Sec) { - std::vector<AddressEntry> Ret; +static std::vector<GdbIndexChunk::AddressEntry> +readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) { + std::vector<GdbIndexChunk::AddressEntry> Ret; - uint32_t CurrentCu = 0; - for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units()) { + uint32_t CuIdx = 0; + for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units()) { DWARFAddressRangesVector Ranges; - CU->collectAddressRanges(Ranges); + Cu->collectAddressRanges(Ranges); ArrayRef<InputSectionBase *> Sections = Sec->File->getSections(); for (DWARFAddressRange &R : Ranges) { @@ -1747,24 +1937,29 @@ static std::vector<AddressEntry> readAddressArea(DWARFContext &Dwarf, // Range list with zero size has no effect. if (R.LowPC == R.HighPC) continue; - Ret.push_back({cast<InputSection>(S), R.LowPC, R.HighPC, CurrentCu}); + auto *IS = cast<InputSection>(S); + uint64_t Offset = IS->getOffsetInFile(); + Ret.push_back({IS, R.LowPC - Offset, R.HighPC - Offset, CuIdx}); } - ++CurrentCu; + ++CuIdx; } return Ret; } -static std::vector<NameTypeEntry> readPubNamesAndTypes(DWARFContext &Dwarf, - bool IsLE) { - StringRef Data[] = {Dwarf.getGnuPubNamesSection(), - Dwarf.getGnuPubTypesSection()}; +static std::vector<GdbIndexChunk::NameTypeEntry> +readPubNamesAndTypes(DWARFContext &Dwarf) { + StringRef Sec1 = Dwarf.getDWARFObj().getGnuPubNamesSection(); + StringRef Sec2 = Dwarf.getDWARFObj().getGnuPubTypesSection(); - std::vector<NameTypeEntry> Ret; - for (StringRef D : Data) { - DWARFDebugPubTable PubTable(D, IsLE, true); - for (const DWARFDebugPubTable::Set &Set : PubTable.getData()) - for (const DWARFDebugPubTable::Entry &Ent : Set.Entries) - Ret.push_back({Ent.Name, Ent.Descriptor.toBits()}); + std::vector<GdbIndexChunk::NameTypeEntry> Ret; + for (StringRef Sec : {Sec1, Sec2}) { + DWARFDebugPubTable Table(Sec, Config->IsLE, true); + for (const DWARFDebugPubTable::Set &Set : Table.getData()) { + for (const DWARFDebugPubTable::Entry &Ent : Set.Entries) { + CachedHashStringRef S(Ent.Name, computeGdbHash(Ent.Name)); + Ret.push_back({S, Ent.Descriptor.toBits()}); + } + } } return Ret; } @@ -1778,119 +1973,140 @@ static std::vector<InputSection *> getDebugInfoSections() { return Ret; } -void GdbIndexSection::buildIndex() { - if (Chunks.empty()) - return; +void GdbIndexSection::fixCuIndex() { + uint32_t Idx = 0; + for (GdbIndexChunk &Chunk : Chunks) { + for (GdbIndexChunk::AddressEntry &Ent : Chunk.AddressAreas) + Ent.CuIndex += Idx; + Idx += Chunk.CompilationUnits.size(); + } +} - uint32_t CuId = 0; - for (GdbIndexChunk &D : Chunks) { - for (AddressEntry &E : D.AddressArea) - E.CuIndex += CuId; - - // Populate constant pool area. - for (NameTypeEntry &NameType : D.NamesAndTypes) { - uint32_t Hash = hash(NameType.Name); - size_t Offset = StringPool.add(NameType.Name); - - bool IsNew; - GdbSymbol *Sym; - std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset); - if (IsNew) { - Sym->CuVectorIndex = CuVectors.size(); - CuVectors.resize(CuVectors.size() + 1); +std::vector<std::vector<uint32_t>> GdbIndexSection::createCuVectors() { + std::vector<std::vector<uint32_t>> Ret; + uint32_t Idx = 0; + uint32_t Off = 0; + + for (GdbIndexChunk &Chunk : Chunks) { + for (GdbIndexChunk::NameTypeEntry &Ent : Chunk.NamesAndTypes) { + GdbSymbol *&Sym = Symbols[Ent.Name]; + if (!Sym) { + Sym = make<GdbSymbol>(GdbSymbol{Ent.Name.hash(), Off, Ret.size()}); + Off += Ent.Name.size() + 1; + Ret.push_back({}); } - CuVectors[Sym->CuVectorIndex].insert(CuId | (NameType.Type << 24)); + // gcc 5.4.1 produces a buggy .debug_gnu_pubnames that contains + // duplicate entries, so we want to dedup them. + std::vector<uint32_t> &Vec = Ret[Sym->CuVectorIndex]; + uint32_t Val = (Ent.Type << 24) | Idx; + if (Vec.empty() || Vec.back() != Val) + Vec.push_back(Val); } - - CuId += D.CompilationUnits.size(); + Idx += Chunk.CompilationUnits.size(); } -} -static GdbIndexChunk readDwarf(DWARFContextInMemory &Dwarf, InputSection *Sec) { - GdbIndexChunk Ret; - Ret.DebugInfoSec = Sec; - Ret.CompilationUnits = readCuList(Dwarf); - Ret.AddressArea = readAddressArea(Dwarf, Sec); - Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE); + StringPoolSize = Off; return Ret; } template <class ELFT> GdbIndexSection *elf::createGdbIndex() { - std::vector<GdbIndexChunk> Chunks; - for (InputSection *Sec : getDebugInfoSections()) { - InputFile *F = Sec->File; - std::error_code EC; - ELFObjectFile<ELFT> Obj(F->MB, EC); - if (EC) - fatal(EC.message()); - DWARFContextInMemory Dwarf(Obj, nullptr, [&](Error E) { - error(toString(F) + ": error parsing DWARF data:\n>>> " + - toString(std::move(E))); - return ErrorPolicy::Continue; - }); - Chunks.push_back(readDwarf(Dwarf, Sec)); - } + // Gather debug info to create a .gdb_index section. + std::vector<InputSection *> Sections = getDebugInfoSections(); + std::vector<GdbIndexChunk> Chunks(Sections.size()); + + parallelForEachN(0, Chunks.size(), [&](size_t I) { + ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>(); + DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File)); + + Chunks[I].DebugInfoSec = Sections[I]; + Chunks[I].CompilationUnits = readCuList(Dwarf); + Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]); + Chunks[I].NamesAndTypes = readPubNamesAndTypes(Dwarf); + }); + + // .debug_gnu_pub{names,types} are useless in executables. + // They are present in input object files solely for creating + // a .gdb_index. So we can remove it from the output. + for (InputSectionBase *S : InputSections) + if (S->Name == ".debug_gnu_pubnames" || S->Name == ".debug_gnu_pubtypes") + S->Live = false; + + // Create a .gdb_index and returns it. return make<GdbIndexSection>(std::move(Chunks)); } -static size_t getCuSize(std::vector<GdbIndexChunk> &C) { +static size_t getCuSize(ArrayRef<GdbIndexChunk> Arr) { size_t Ret = 0; - for (GdbIndexChunk &D : C) + for (const GdbIndexChunk &D : Arr) Ret += D.CompilationUnits.size(); return Ret; } -static size_t getAddressAreaSize(std::vector<GdbIndexChunk> &C) { +static size_t getAddressAreaSize(ArrayRef<GdbIndexChunk> Arr) { size_t Ret = 0; - for (GdbIndexChunk &D : C) - Ret += D.AddressArea.size(); + for (const GdbIndexChunk &D : Arr) + Ret += D.AddressAreas.size(); return Ret; } -void GdbIndexSection::finalizeContents() { - if (Finalized) - return; - Finalized = true; +std::vector<GdbSymbol *> GdbIndexSection::createGdbSymtab() { + uint32_t Size = NextPowerOf2(Symbols.size() * 4 / 3); + if (Size < 1024) + Size = 1024; - buildIndex(); + uint32_t Mask = Size - 1; + std::vector<GdbSymbol *> Ret(Size); - SymbolTable.finalizeContents(); + for (auto &KV : Symbols) { + GdbSymbol *Sym = KV.second; + uint32_t I = Sym->NameHash & Mask; + uint32_t Step = ((Sym->NameHash * 17) & Mask) | 1; - // GdbIndex header consist from version fields - // and 5 more fields with different kinds of offsets. - CuTypesOffset = CuListOffset + getCuSize(Chunks) * CompilationUnitSize; - SymTabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * AddressEntrySize; + while (Ret[I]) + I = (I + Step) & Mask; + Ret[I] = Sym; + } + return Ret; +} - ConstantPoolOffset = - SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize; +GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&C) + : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"), Chunks(std::move(C)) { + fixCuIndex(); + CuVectors = createCuVectors(); + GdbSymtab = createGdbSymtab(); - for (std::set<uint32_t> &CuVec : CuVectors) { - CuVectorsOffset.push_back(CuVectorsSize); - CuVectorsSize += OffsetTypeSize * (CuVec.size() + 1); - } - StringPoolOffset = ConstantPoolOffset + CuVectorsSize; + // Compute offsets early to know the section size. + // Each chunk size needs to be in sync with what we write in writeTo. + CuTypesOffset = CuListOffset + getCuSize(Chunks) * 16; + SymtabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * 20; + ConstantPoolOffset = SymtabOffset + GdbSymtab.size() * 8; - StringPool.finalizeInOrder(); + size_t Off = 0; + for (ArrayRef<uint32_t> Vec : CuVectors) { + CuVectorOffsets.push_back(Off); + Off += (Vec.size() + 1) * 4; + } + StringPoolOffset = ConstantPoolOffset + Off; } size_t GdbIndexSection::getSize() const { - const_cast<GdbIndexSection *>(this)->finalizeContents(); - return StringPoolOffset + StringPool.getSize(); + return StringPoolOffset + StringPoolSize; } void GdbIndexSection::writeTo(uint8_t *Buf) { - write32le(Buf, 7); // Write version. - write32le(Buf + 4, CuListOffset); // CU list offset. - write32le(Buf + 8, CuTypesOffset); // Types CU list offset. - write32le(Buf + 12, CuTypesOffset); // Address area offset. - write32le(Buf + 16, SymTabOffset); // Symbol table offset. - write32le(Buf + 20, ConstantPoolOffset); // Constant pool offset. + // Write the section header. + write32le(Buf, 7); + write32le(Buf + 4, CuListOffset); + write32le(Buf + 8, CuTypesOffset); + write32le(Buf + 12, CuTypesOffset); + write32le(Buf + 16, SymtabOffset); + write32le(Buf + 20, ConstantPoolOffset); Buf += 24; // Write the CU list. for (GdbIndexChunk &D : Chunks) { - for (CompilationUnitEntry &Cu : D.CompilationUnits) { + for (GdbIndexChunk::CuEntry &Cu : D.CompilationUnits) { write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset); write64le(Buf + 8, Cu.CuLength); Buf += 16; @@ -1899,7 +2115,7 @@ void GdbIndexSection::writeTo(uint8_t *Buf) { // Write the address area. for (GdbIndexChunk &D : Chunks) { - for (AddressEntry &E : D.AddressArea) { + for (GdbIndexChunk::AddressEntry &E : D.AddressAreas) { uint64_t BaseAddr = E.Section->getParent()->Addr + E.Section->getOffset(0); write64le(Buf, BaseAddr + E.LowAddress); @@ -1910,43 +2126,47 @@ void GdbIndexSection::writeTo(uint8_t *Buf) { } // Write the symbol table. - for (size_t I = 0; I < SymbolTable.getCapacity(); ++I) { - GdbSymbol *Sym = SymbolTable.getSymbol(I); + for (GdbSymbol *Sym : GdbSymtab) { if (Sym) { - size_t NameOffset = - Sym->NameOffset + StringPoolOffset - ConstantPoolOffset; - size_t CuVectorOffset = CuVectorsOffset[Sym->CuVectorIndex]; - write32le(Buf, NameOffset); - write32le(Buf + 4, CuVectorOffset); + write32le(Buf, Sym->NameOffset + StringPoolOffset - ConstantPoolOffset); + write32le(Buf + 4, CuVectorOffsets[Sym->CuVectorIndex]); } Buf += 8; } - // Write the CU vectors into the constant pool. - for (std::set<uint32_t> &CuVec : CuVectors) { - write32le(Buf, CuVec.size()); + // Write the CU vectors. + for (ArrayRef<uint32_t> Vec : CuVectors) { + write32le(Buf, Vec.size()); Buf += 4; - for (uint32_t Val : CuVec) { + for (uint32_t Val : Vec) { write32le(Buf, Val); Buf += 4; } } - StringPool.write(Buf); + // Write the string pool. + for (auto &KV : Symbols) { + CachedHashStringRef S = KV.first; + GdbSymbol *Sym = KV.second; + size_t Off = Sym->NameOffset; + memcpy(Buf + Off, S.val().data(), S.size()); + Buf[Off + S.size()] = '\0'; + } } bool GdbIndexSection::empty() const { return !Out::DebugInfo; } -template <class ELFT> -EhFrameHeader<ELFT>::EhFrameHeader() +EhFrameHeader::EhFrameHeader() : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {} // .eh_frame_hdr contains a binary search table of pointers to FDEs. // Each entry of the search table consists of two values, // the starting PC from where FDEs covers, and the FDE's address. // It is sorted by PC. -template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) { - const endianness E = ELFT::TargetEndianness; +void EhFrameHeader::writeTo(uint8_t *Buf) { + typedef EhFrameSection::FdeData FdeData; + + std::vector<FdeData> Fdes = InX::EhFrame->getFdeData(); // Sort the FDE list by their PC and uniqueify. Usually there is only // one FDE for a PC (i.e. function), but if ICF merges two functions @@ -1960,31 +2180,24 @@ template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) { Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; Buf[2] = DW_EH_PE_udata4; Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; - write32<E>(Buf + 4, In<ELFT>::EhFrame->getParent()->Addr - this->getVA() - 4); - write32<E>(Buf + 8, Fdes.size()); + write32(Buf + 4, InX::EhFrame->getParent()->Addr - this->getVA() - 4); + write32(Buf + 8, Fdes.size()); Buf += 12; uint64_t VA = this->getVA(); for (FdeData &Fde : Fdes) { - write32<E>(Buf, Fde.Pc - VA); - write32<E>(Buf + 4, Fde.FdeVA - VA); + write32(Buf, Fde.Pc - VA); + write32(Buf + 4, Fde.FdeVA - VA); Buf += 8; } } -template <class ELFT> size_t EhFrameHeader<ELFT>::getSize() const { +size_t EhFrameHeader::getSize() const { // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. - return 12 + In<ELFT>::EhFrame->NumFdes * 8; -} - -template <class ELFT> -void EhFrameHeader<ELFT>::addFde(uint32_t Pc, uint32_t FdeVA) { - Fdes.push_back({Pc, FdeVA}); + return 12 + InX::EhFrame->NumFdes * 8; } -template <class ELFT> bool EhFrameHeader<ELFT>::empty() const { - return In<ELFT>::EhFrame->empty(); -} +bool EhFrameHeader::empty() const { return InX::EhFrame->empty(); } template <class ELFT> VersionDefinitionSection<ELFT>::VersionDefinitionSection() @@ -2065,7 +2278,7 @@ template <class ELFT> size_t VersionTableSection<ELFT>::getSize() const { template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) { auto *OutVersym = reinterpret_cast<Elf_Versym *>(Buf) + 1; for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) { - OutVersym->vs_index = S.Symbol->symbol()->VersionId; + OutVersym->vs_index = S.Sym->VersionId; ++OutVersym; } } @@ -2086,14 +2299,13 @@ VersionNeedSection<ELFT>::VersionNeedSection() template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) { - auto *Ver = reinterpret_cast<const typename ELFT::Verdef *>(SS->Verdef); + SharedFile<ELFT> *File = SS->getFile<ELFT>(); + const typename ELFT::Verdef *Ver = File->Verdefs[SS->VerdefIndex]; if (!Ver) { - SS->symbol()->VersionId = VER_NDX_GLOBAL; + SS->VersionId = VER_NDX_GLOBAL; return; } - auto *File = cast<SharedFile<ELFT>>(SS->File); - // If we don't already know that we need an Elf_Verneed for this DSO, prepare // to create one by adding it to our needed list and creating a dynstr entry // for the soname. @@ -2108,7 +2320,7 @@ void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) { Ver->getAux()->vda_name); NV.Index = NextIndex++; } - SS->symbol()->VersionId = NV.Index; + SS->VersionId = NV.Index; } template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) { @@ -2162,23 +2374,21 @@ template <class ELFT> bool VersionNeedSection<ELFT>::empty() const { return getNeedNum() == 0; } -MergeSyntheticSection::MergeSyntheticSection(StringRef Name, uint32_t Type, - uint64_t Flags, uint32_t Alignment) - : SyntheticSection(Flags, Type, Alignment, Name), - Builder(StringTableBuilder::RAW, Alignment) {} - void MergeSyntheticSection::addSection(MergeInputSection *MS) { MS->Parent = this; Sections.push_back(MS); } -void MergeSyntheticSection::writeTo(uint8_t *Buf) { Builder.write(Buf); } +MergeTailSection::MergeTailSection(StringRef Name, uint32_t Type, + uint64_t Flags, uint32_t Alignment) + : MergeSyntheticSection(Name, Type, Flags, Alignment), + Builder(StringTableBuilder::RAW, Alignment) {} -bool MergeSyntheticSection::shouldTailMerge() const { - return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2; -} +size_t MergeTailSection::getSize() const { return Builder.getSize(); } + +void MergeTailSection::writeTo(uint8_t *Buf) { Builder.write(Buf); } -void MergeSyntheticSection::finalizeTailMerge() { +void MergeTailSection::finalizeContents() { // Add all string pieces to the string table builder to create section // contents. for (MergeInputSection *Sec : Sections) @@ -2198,46 +2408,98 @@ void MergeSyntheticSection::finalizeTailMerge() { Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I)); } -void MergeSyntheticSection::finalizeNoTailMerge() { - // Add all string pieces to the string table builder to create section - // contents. Because we are not tail-optimizing, offsets of strings are - // fixed when they are added to the builder (string table builder contains - // a hash table from strings to offsets). - for (MergeInputSection *Sec : Sections) +void MergeNoTailSection::writeTo(uint8_t *Buf) { + for (size_t I = 0; I < NumShards; ++I) + Shards[I].write(Buf + ShardOffsets[I]); +} + +// This function is very hot (i.e. it can take several seconds to finish) +// because sometimes the number of inputs is in an order of magnitude of +// millions. So, we use multi-threading. +// +// For any strings S and T, we know S is not mergeable with T if S's hash +// value is different from T's. If that's the case, we can safely put S and +// T into different string builders without worrying about merge misses. +// We do it in parallel. +void MergeNoTailSection::finalizeContents() { + // Initializes string table builders. + for (size_t I = 0; I < NumShards; ++I) + Shards.emplace_back(StringTableBuilder::RAW, Alignment); + + // Concurrency level. Must be a power of 2 to avoid expensive modulo + // operations in the following tight loop. + size_t Concurrency = 1; + if (ThreadsEnabled) + Concurrency = + std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards); + + // Add section pieces to the builders. + parallelForEachN(0, Concurrency, [&](size_t ThreadId) { + for (MergeInputSection *Sec : Sections) { + for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) { + if (!Sec->Pieces[I].Live) + continue; + size_t ShardId = getShardId(Sec->Pieces[I].Hash); + if ((ShardId & (Concurrency - 1)) == ThreadId) + Sec->Pieces[I].OutputOff = Shards[ShardId].add(Sec->getData(I)); + } + } + }); + + // Compute an in-section offset for each shard. + size_t Off = 0; + for (size_t I = 0; I < NumShards; ++I) { + Shards[I].finalizeInOrder(); + if (Shards[I].getSize() > 0) + Off = alignTo(Off, Alignment); + ShardOffsets[I] = Off; + Off += Shards[I].getSize(); + } + Size = Off; + + // So far, section pieces have offsets from beginning of shards, but + // we want offsets from beginning of the whole section. Fix them. + parallelForEach(Sections, [&](MergeInputSection *Sec) { for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) if (Sec->Pieces[I].Live) - Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I)); + Sec->Pieces[I].OutputOff += + ShardOffsets[getShardId(Sec->Pieces[I].Hash)]; + }); +} - Builder.finalizeInOrder(); +static MergeSyntheticSection *createMergeSynthetic(StringRef Name, + uint32_t Type, + uint64_t Flags, + uint32_t Alignment) { + bool ShouldTailMerge = (Flags & SHF_STRINGS) && Config->Optimize >= 2; + if (ShouldTailMerge) + return make<MergeTailSection>(Name, Type, Flags, Alignment); + return make<MergeNoTailSection>(Name, Type, Flags, Alignment); } -void MergeSyntheticSection::finalizeContents() { - if (shouldTailMerge()) - finalizeTailMerge(); - else - finalizeNoTailMerge(); -} - -size_t MergeSyntheticSection::getSize() const { return Builder.getSize(); } - -// This function decompresses compressed sections and scans over the input -// sections to create mergeable synthetic sections. It removes -// MergeInputSections from the input section array and adds new synthetic -// sections at the location of the first input section that it replaces. It then -// finalizes each synthetic section in order to compute an output offset for -// each piece of each input section. -void elf::decompressAndMergeSections() { - // splitIntoPieces needs to be called on each MergeInputSection before calling - // finalizeContents(). Do that first. - parallelForEach(InputSections.begin(), InputSections.end(), - [](InputSectionBase *S) { - if (!S->Live) - return; - if (Decompressor::isCompressedELFSection(S->Flags, S->Name)) - S->uncompress(); - if (auto *MS = dyn_cast<MergeInputSection>(S)) - MS->splitIntoPieces(); - }); +// Debug sections may be compressed by zlib. Uncompress if exists. +void elf::decompressSections() { + parallelForEach(InputSections, [](InputSectionBase *Sec) { + if (Sec->Live) + Sec->maybeUncompress(); + }); +} + +// This function scans over the inputsections to create mergeable +// synthetic sections. +// +// It removes MergeInputSections from the input section array and adds +// new synthetic sections at the location of the first input section +// that it replaces. It then finalizes each synthetic section in order +// to compute an output offset for each piece of each input section. +void elf::mergeSections() { + // splitIntoPieces needs to be called on each MergeInputSection + // before calling finalizeContents(). Do that first. + parallelForEach(InputSections, [](InputSectionBase *Sec) { + if (Sec->Live) + if (auto *S = dyn_cast<MergeInputSection>(Sec)) + S->splitIntoPieces(); + }); std::vector<MergeSyntheticSection *> MergeSections; for (InputSectionBase *&S : InputSections) { @@ -2250,20 +2512,28 @@ void elf::decompressAndMergeSections() { if (!MS->Live) continue; - StringRef OutsecName = getOutputSectionName(MS->Name); - uint64_t Flags = MS->Flags & ~(uint64_t)SHF_GROUP; + StringRef OutsecName = getOutputSectionName(MS); uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize); auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) { - return Sec->Name == OutsecName && Sec->Flags == Flags && - Sec->Alignment == Alignment; + // While we could create a single synthetic section for two different + // values of Entsize, it is better to take Entsize into consideration. + // + // With a single synthetic section no two pieces with different Entsize + // could be equal, so we may as well have two sections. + // + // Using Entsize in here also allows us to propagate it to the synthetic + // section. + return Sec->Name == OutsecName && Sec->Flags == MS->Flags && + Sec->Entsize == MS->Entsize && Sec->Alignment == Alignment; }); if (I == MergeSections.end()) { MergeSyntheticSection *Syn = - make<MergeSyntheticSection>(OutsecName, MS->Type, Flags, Alignment); + createMergeSynthetic(OutsecName, MS->Type, MS->Flags, Alignment); MergeSections.push_back(Syn); I = std::prev(MergeSections.end()); S = Syn; + Syn->Entsize = MS->Entsize; } else { S = nullptr; } @@ -2293,20 +2563,27 @@ ARMExidxSentinelSection::ARMExidxSentinelSection() void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { // The Sections are sorted in order of ascending PREL31 address with the // sentinel last. We need to find the InputSection that precedes the - // sentinel. By construction the Sentinel is in the last - // InputSectionDescription as the InputSection that precedes it. - OutputSectionCommand *C = Script->getCmd(getParent()); - auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(), - [](const BaseCommand *Base) { - return isa<InputSectionDescription>(Base); - }); - auto L = cast<InputSectionDescription>(*ISD); - InputSection *Highest = L->Sections[L->Sections.size() - 2]; + // sentinel. + OutputSection *C = getParent(); + InputSection *Highest = nullptr; + unsigned Skip = 1; + for (const BaseCommand *Base : llvm::reverse(C->SectionCommands)) { + if (!isa<InputSectionDescription>(Base)) + continue; + auto L = cast<InputSectionDescription>(Base); + if (Skip >= L->Sections.size()) { + Skip -= L->Sections.size(); + continue; + } + Highest = L->Sections[L->Sections.size() - Skip - 1]; + break; + } + assert(Highest); InputSection *LS = Highest->getLinkOrderDep(); uint64_t S = LS->getParent()->Addr + LS->getOffset(LS->getSize()); uint64_t P = getVA(); Target->relocateOne(Buf, R_ARM_PREL31, S - P); - write32le(Buf + 4, 0x1); + write32le(Buf + 4, 1); } ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off) @@ -2330,6 +2607,8 @@ void ThunkSection::writeTo(uint8_t *Buf) { } InputSection *ThunkSection::getTargetInputSection() const { + if (Thunks.empty()) + return nullptr; const Thunk *T = Thunks.front(); return T->getTargetInputSection(); } @@ -2338,7 +2617,8 @@ InputSection *InX::ARMAttributes; BssSection *InX::Bss; BssSection *InX::BssRelRo; BuildIdSection *InX::BuildId; -InputSection *InX::Common; +EhFrameHeader *InX::EhFrameHdr; +EhFrameSection *InX::EhFrame; SyntheticSection *InX::Dynamic; StringTableSection *InX::DynStrTab; SymbolTableBaseSection *InX::DynSymTab; @@ -2347,11 +2627,15 @@ GdbIndexSection *InX::GdbIndex; GotSection *InX::Got; GotPltSection *InX::GotPlt; GnuHashTableSection *InX::GnuHashTab; +HashTableSection *InX::HashTab; IgotPltSection *InX::IgotPlt; MipsGotSection *InX::MipsGot; MipsRldMapSection *InX::MipsRldMap; PltSection *InX::Plt; PltSection *InX::Iplt; +RelocationBaseSection *InX::RelaDyn; +RelocationBaseSection *InX::RelaPlt; +RelocationBaseSection *InX::RelaIplt; StringTableSection *InX::ShStrTab; StringTableSection *InX::StrTab; SymbolTableBaseSection *InX::SymTab; @@ -2361,15 +2645,15 @@ template GdbIndexSection *elf::createGdbIndex<ELF32BE>(); template GdbIndexSection *elf::createGdbIndex<ELF64LE>(); template GdbIndexSection *elf::createGdbIndex<ELF64BE>(); -template void PltSection::addEntry<ELF32LE>(SymbolBody &Sym); -template void PltSection::addEntry<ELF32BE>(SymbolBody &Sym); -template void PltSection::addEntry<ELF64LE>(SymbolBody &Sym); -template void PltSection::addEntry<ELF64BE>(SymbolBody &Sym); +template void EhFrameSection::addSection<ELF32LE>(InputSectionBase *); +template void EhFrameSection::addSection<ELF32BE>(InputSectionBase *); +template void EhFrameSection::addSection<ELF64LE>(InputSectionBase *); +template void EhFrameSection::addSection<ELF64BE>(InputSectionBase *); -template InputSection *elf::createCommonSection<ELF32LE>(); -template InputSection *elf::createCommonSection<ELF32BE>(); -template InputSection *elf::createCommonSection<ELF64LE>(); -template InputSection *elf::createCommonSection<ELF64BE>(); +template void PltSection::addEntry<ELF32LE>(Symbol &Sym); +template void PltSection::addEntry<ELF32BE>(Symbol &Sym); +template void PltSection::addEntry<ELF64LE>(Symbol &Sym); +template void PltSection::addEntry<ELF64BE>(Symbol &Sym); template MergeInputSection *elf::createCommentSection<ELF32LE>(); template MergeInputSection *elf::createCommentSection<ELF32BE>(); @@ -2401,21 +2685,16 @@ template class elf::RelocationSection<ELF32BE>; template class elf::RelocationSection<ELF64LE>; template class elf::RelocationSection<ELF64BE>; +template class elf::AndroidPackedRelocationSection<ELF32LE>; +template class elf::AndroidPackedRelocationSection<ELF32BE>; +template class elf::AndroidPackedRelocationSection<ELF64LE>; +template class elf::AndroidPackedRelocationSection<ELF64BE>; + template class elf::SymbolTableSection<ELF32LE>; template class elf::SymbolTableSection<ELF32BE>; template class elf::SymbolTableSection<ELF64LE>; template class elf::SymbolTableSection<ELF64BE>; -template class elf::HashTableSection<ELF32LE>; -template class elf::HashTableSection<ELF32BE>; -template class elf::HashTableSection<ELF64LE>; -template class elf::HashTableSection<ELF64BE>; - -template class elf::EhFrameHeader<ELF32LE>; -template class elf::EhFrameHeader<ELF32BE>; -template class elf::EhFrameHeader<ELF64LE>; -template class elf::EhFrameHeader<ELF64BE>; - template class elf::VersionTableSection<ELF32LE>; template class elf::VersionTableSection<ELF32BE>; template class elf::VersionTableSection<ELF64LE>; @@ -2430,8 +2709,3 @@ template class elf::VersionDefinitionSection<ELF32LE>; template class elf::VersionDefinitionSection<ELF32BE>; template class elf::VersionDefinitionSection<ELF64LE>; template class elf::VersionDefinitionSection<ELF64BE>; - -template class elf::EhFrameSection<ELF32LE>; -template class elf::EhFrameSection<ELF32BE>; -template class elf::EhFrameSection<ELF64LE>; -template class elf::EhFrameSection<ELF64BE>; diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index ccf021ec9597..5aaf479f3e35 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -26,11 +26,11 @@ #include "InputSection.h" #include "llvm/ADT/MapVector.h" #include "llvm/MC/StringTableBuilder.h" - -#include <set> +#include <functional> namespace lld { namespace elf { +class SharedSymbol; class SyntheticSection : public InputSection { public: @@ -47,7 +47,7 @@ public: virtual void finalizeContents() {} // If the section has the SHF_ALLOC flag and the size may be changed if // thunks are added, update the section size. - virtual void updateAllocSize() {} + virtual bool updateAllocSize() { return false; } // If any additional finalization of contents are needed post thunk creation. virtual void postThunkContents() {} virtual bool empty() const { return false; } @@ -59,21 +59,12 @@ public: }; struct CieRecord { - EhSectionPiece *Piece = nullptr; - std::vector<EhSectionPiece *> FdePieces; + EhSectionPiece *Cie = nullptr; + std::vector<EhSectionPiece *> Fdes; }; // Section for .eh_frame. -template <class ELFT> class EhFrameSection final : public SyntheticSection { - typedef typename ELFT::Shdr Elf_Shdr; - typedef typename ELFT::Rel Elf_Rel; - typedef typename ELFT::Rela Elf_Rela; - - void updateAlignment(uint64_t Val) { - if (Val > this->Alignment) - this->Alignment = Val; - } - +class EhFrameSection final : public SyntheticSection { public: EhFrameSection(); void writeTo(uint8_t *Buf) override; @@ -81,30 +72,36 @@ public: bool empty() const override { return Sections.empty(); } size_t getSize() const override { return Size; } - void addSection(InputSectionBase *S); + template <class ELFT> void addSection(InputSectionBase *S); + std::vector<EhInputSection *> Sections; size_t NumFdes = 0; - std::vector<EhInputSection *> Sections; + struct FdeData { + uint32_t Pc; + uint32_t FdeVA; + }; + + std::vector<FdeData> getFdeData() const; private: uint64_t Size = 0; - template <class RelTy> + + template <class ELFT, class RelTy> void addSectionAux(EhInputSection *S, llvm::ArrayRef<RelTy> Rels); - template <class RelTy> + template <class ELFT, class RelTy> CieRecord *addCie(EhSectionPiece &Piece, ArrayRef<RelTy> Rels); - template <class RelTy> + template <class ELFT, class RelTy> bool isFdeLive(EhSectionPiece &Piece, ArrayRef<RelTy> Rels); - uint64_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc); + uint64_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc) const; - std::vector<CieRecord *> Cies; + std::vector<CieRecord *> CieRecords; // CIE records are uniquified by their contents and personality functions. - llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord *> - CieMap; + llvm::DenseMap<std::pair<ArrayRef<uint8_t>, Symbol *>, CieRecord *> CieMap; }; class GotSection : public SyntheticSection { @@ -115,11 +112,11 @@ public: bool empty() const override; void writeTo(uint8_t *Buf) override; - void addEntry(SymbolBody &Sym); - bool addDynTlsEntry(SymbolBody &Sym); + void addEntry(Symbol &Sym); + bool addDynTlsEntry(Symbol &Sym); bool addTlsIndex(); - uint64_t getGlobalDynAddr(const SymbolBody &B) const; - uint64_t getGlobalDynOffset(const SymbolBody &B) const; + uint64_t getGlobalDynAddr(const Symbol &B) const; + uint64_t getGlobalDynOffset(const Symbol &B) const; uint64_t getTlsIndexVA() { return this->getVA() + TlsIndexOff; } uint32_t getTlsIndexOff() const { return TlsIndexOff; } @@ -159,14 +156,13 @@ private: // respectively. class BssSection final : public SyntheticSection { public: - BssSection(StringRef Name); + BssSection(StringRef Name, uint64_t Size, uint32_t Alignment); void writeTo(uint8_t *) override {} bool empty() const override { return getSize() == 0; } - size_t reserveSpace(uint64_t Size, uint32_t Alignment); size_t getSize() const override { return Size; } -private: - uint64_t Size = 0; + static bool classof(const SectionBase *S) { return S->Bss; } + uint64_t Size; }; class MipsGotSection final : public SyntheticSection { @@ -174,21 +170,21 @@ public: MipsGotSection(); void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } - void updateAllocSize() override; + bool updateAllocSize() override; void finalizeContents() override; bool empty() const override; - void addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr); - bool addDynTlsEntry(SymbolBody &Sym); + void addEntry(Symbol &Sym, int64_t Addend, RelExpr Expr); + bool addDynTlsEntry(Symbol &Sym); bool addTlsIndex(); - uint64_t getPageEntryOffset(const SymbolBody &B, int64_t Addend) const; - uint64_t getBodyEntryOffset(const SymbolBody &B, int64_t Addend) const; - uint64_t getGlobalDynOffset(const SymbolBody &B) const; + uint64_t getPageEntryOffset(const Symbol &B, int64_t Addend) const; + uint64_t getSymEntryOffset(const Symbol &B, int64_t Addend) const; + uint64_t getGlobalDynOffset(const Symbol &B) const; // Returns the symbol which corresponds to the first entry of the global part // of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic // table properties. // Returns nullptr if the global part is empty. - const SymbolBody *getFirstGlobalEntry() const; + const Symbol *getFirstGlobalEntry() const; // Returns the number of entries in the local part of GOT including // the number of reserved entries. @@ -248,7 +244,7 @@ private: // to the first index of "Page" entries allocated for this section. llvm::SmallMapVector<const OutputSection *, size_t, 16> PageIndexMap; - typedef std::pair<const SymbolBody *, uint64_t> GotEntry; + typedef std::pair<const Symbol *, uint64_t> GotEntry; typedef std::vector<GotEntry> GotEntries; // Map from Symbol-Addend pair to the GOT index. llvm::DenseMap<GotEntry, size_t> EntryIndexMap; @@ -261,7 +257,7 @@ private: GotEntries GlobalEntries; // TLS entries. - std::vector<const SymbolBody *> TlsEntries; + std::vector<const Symbol *> TlsEntries; uint32_t TlsIndexOff = -1; uint64_t Size = 0; @@ -270,13 +266,13 @@ private: class GotPltSection final : public SyntheticSection { public: GotPltSection(); - void addEntry(SymbolBody &Sym); + void addEntry(Symbol &Sym); size_t getSize() const override; void writeTo(uint8_t *Buf) override; bool empty() const override { return Entries.empty(); } private: - std::vector<const SymbolBody *> Entries; + std::vector<const Symbol *> Entries; }; // The IgotPltSection is a Got associated with the PltSection for GNU Ifunc @@ -286,13 +282,13 @@ private: class IgotPltSection final : public SyntheticSection { public: IgotPltSection(); - void addEntry(SymbolBody &Sym); + void addEntry(Symbol &Sym); size_t getSize() const override; void writeTo(uint8_t *Buf) override; bool empty() const override { return Entries.empty(); } private: - std::vector<const SymbolBody *> Entries; + std::vector<const Symbol *> Entries; }; class StringTableSection final : public SyntheticSection { @@ -315,8 +311,7 @@ private: class DynamicReloc { public: DynamicReloc(uint32_t Type, const InputSectionBase *InputSec, - uint64_t OffsetInSec, bool UseSymVA, SymbolBody *Sym, - int64_t Addend) + uint64_t OffsetInSec, bool UseSymVA, Symbol *Sym, int64_t Addend) : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec), UseSymVA(UseSymVA), Addend(Addend) {} @@ -328,7 +323,7 @@ public: uint32_t Type; private: - SymbolBody *Sym; + Symbol *Sym; const InputSectionBase *InputSec = nullptr; uint64_t OffsetInSec; bool UseSymVA; @@ -342,30 +337,8 @@ template <class ELFT> class DynamicSection final : public SyntheticSection { typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Sym Elf_Sym; - // The .dynamic section contains information for the dynamic linker. - // The section consists of fixed size entries, which consist of - // type and value fields. Value are one of plain integers, symbol - // addresses, or section addresses. This struct represents the entry. - struct Entry { - int32_t Tag; - union { - OutputSection *OutSec; - InputSection *InSec; - uint64_t Val; - const SymbolBody *Sym; - }; - enum KindT { SecAddr, SecSize, SymAddr, PlainInt, InSecAddr } Kind; - Entry(int32_t Tag, OutputSection *OutSec, KindT Kind = SecAddr) - : Tag(Tag), OutSec(OutSec), Kind(Kind) {} - Entry(int32_t Tag, InputSection *Sec) - : Tag(Tag), InSec(Sec), Kind(InSecAddr) {} - Entry(int32_t Tag, uint64_t Val) : Tag(Tag), Val(Val), Kind(PlainInt) {} - Entry(int32_t Tag, const SymbolBody *Sym) - : Tag(Tag), Sym(Sym), Kind(SymAddr) {} - }; - // finalizeContents() fills this vector with the section contents. - std::vector<Entry> Entries; + std::vector<std::pair<int32_t, std::function<uint64_t()>>> Entries; public: DynamicSection(); @@ -374,33 +347,66 @@ public: size_t getSize() const override { return Size; } private: - void addEntries(); - void add(Entry E) { Entries.push_back(E); } + void add(int32_t Tag, std::function<uint64_t()> Fn); + void addInt(int32_t Tag, uint64_t Val); + void addInSec(int32_t Tag, InputSection *Sec); + void addOutSec(int32_t Tag, OutputSection *Sec); + void addSize(int32_t Tag, OutputSection *Sec); + void addSym(int32_t Tag, Symbol *Sym); + uint64_t Size = 0; }; -template <class ELFT> class RelocationSection final : public SyntheticSection { +class RelocationBaseSection : public SyntheticSection { +public: + RelocationBaseSection(StringRef Name, uint32_t Type, int32_t DynamicTag, + int32_t SizeDynamicTag); + void addReloc(const DynamicReloc &Reloc); + bool empty() const override { return Relocs.empty(); } + size_t getSize() const override { return Relocs.size() * this->Entsize; } + size_t getRelativeRelocCount() const { return NumRelativeRelocs; } + void finalizeContents() override; + int32_t DynamicTag, SizeDynamicTag; + +protected: + std::vector<DynamicReloc> Relocs; + size_t NumRelativeRelocs = 0; +}; + +template <class ELFT> +class RelocationSection final : public RelocationBaseSection { typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; public: RelocationSection(StringRef Name, bool Sort); - void addReloc(const DynamicReloc &Reloc); unsigned getRelocOffset(); - void finalizeContents() override; void writeTo(uint8_t *Buf) override; - bool empty() const override { return Relocs.empty(); } - size_t getSize() const override { return Relocs.size() * this->Entsize; } - size_t getRelativeRelocCount() const { return NumRelativeRelocs; } private: bool Sort; - size_t NumRelativeRelocs = 0; - std::vector<DynamicReloc> Relocs; +}; + +template <class ELFT> +class AndroidPackedRelocationSection final : public RelocationBaseSection { + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Rela Elf_Rela; + +public: + AndroidPackedRelocationSection(StringRef Name); + + bool updateAllocSize() override; + size_t getSize() const override { return RelocData.size(); } + void writeTo(uint8_t *Buf) override { + memcpy(Buf, RelocData.data(), RelocData.size()); + } + +private: + SmallVector<char, 0> RelocData; }; struct SymbolTableEntry { - SymbolBody *Symbol; + Symbol *Sym; size_t StrTabOffset; }; @@ -410,9 +416,9 @@ public: void finalizeContents() override; void postThunkContents() override; size_t getSize() const override { return getNumSymbols() * Entsize; } - void addSymbol(SymbolBody *Body); + void addSymbol(Symbol *Sym); unsigned getNumSymbols() const { return Symbols.size() + 1; } - size_t getSymbolIndex(SymbolBody *Body); + size_t getSymbolIndex(Symbol *Sym); ArrayRef<SymbolTableEntry> getSymbols() const { return Symbols; } protected: @@ -420,6 +426,10 @@ protected: std::vector<SymbolTableEntry> Symbols; StringTableSection &StrTabSec; + + llvm::once_flag OnceFlag; + llvm::DenseMap<Symbol *, size_t> SymbolIndexMap; + llvm::DenseMap<OutputSection *, size_t> SectionIndexMap; }; template <class ELFT> @@ -451,9 +461,10 @@ private: void writeHashTable(uint8_t *Buf); struct Entry { - SymbolBody *Body; + Symbol *Sym; size_t StrTabOffset; uint32_t Hash; + uint32_t BucketIdx; }; std::vector<Entry> Symbols; @@ -462,7 +473,7 @@ private: size_t Size = 0; }; -template <class ELFT> class HashTableSection final : public SyntheticSection { +class HashTableSection final : public SyntheticSection { public: HashTableSection(); void finalizeContents() override; @@ -485,57 +496,81 @@ public: bool empty() const override { return Entries.empty(); } void addSymbols(); - template <class ELFT> void addEntry(SymbolBody &Sym); + template <class ELFT> void addEntry(Symbol &Sym); private: - void writeHeader(uint8_t *Buf){}; - void addHeaderSymbols(){}; unsigned getPltRelocOff() const; - std::vector<std::pair<const SymbolBody *, unsigned>> Entries; + std::vector<std::pair<const Symbol *, unsigned>> Entries; // Iplt always has HeaderSize of 0, the Plt HeaderSize is always non-zero size_t HeaderSize; }; -class GdbIndexSection final : public SyntheticSection { - const unsigned OffsetTypeSize = 4; - const unsigned CuListOffset = 6 * OffsetTypeSize; - const unsigned CompilationUnitSize = 16; - const unsigned AddressEntrySize = 16 + OffsetTypeSize; - const unsigned SymTabEntrySize = 2 * OffsetTypeSize; +// GdbIndexChunk is created for each .debug_info section and contains +// information to create a part of .gdb_index for a given input section. +struct GdbIndexChunk { + struct AddressEntry { + InputSection *Section; + uint64_t LowAddress; + uint64_t HighAddress; + uint32_t CuIndex; + }; + + struct CuEntry { + uint64_t CuOffset; + uint64_t CuLength; + }; + + struct NameTypeEntry { + llvm::CachedHashStringRef Name; + uint8_t Type; + }; + InputSection *DebugInfoSec; + std::vector<AddressEntry> AddressAreas; + std::vector<CuEntry> CompilationUnits; + std::vector<NameTypeEntry> NamesAndTypes; +}; + +// The symbol type for the .gdb_index section. +struct GdbSymbol { + uint32_t NameHash; + size_t NameOffset; + size_t CuVectorIndex; +}; + +class GdbIndexSection final : public SyntheticSection { public: GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks); - void finalizeContents() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override; bool empty() const override; - // Symbol table is a hash table for types and names. - // It is the area of gdb index. - GdbHashTab SymbolTable; +private: + void fixCuIndex(); + std::vector<std::vector<uint32_t>> createCuVectors(); + std::vector<GdbSymbol *> createGdbSymtab(); + + // A symbol table for this .gdb_index section. + std::vector<GdbSymbol *> GdbSymtab; // CU vector is a part of constant pool area of section. - std::vector<std::set<uint32_t>> CuVectors; + std::vector<std::vector<uint32_t>> CuVectors; - // String pool is also a part of constant pool, it follows CU vectors. - llvm::StringTableBuilder StringPool; + // Symbol table contents. + llvm::DenseMap<llvm::CachedHashStringRef, GdbSymbol *> Symbols; // Each chunk contains information gathered from a debug sections of single // object and used to build different areas of gdb index. std::vector<GdbIndexChunk> Chunks; -private: - void buildIndex(); - + static constexpr uint32_t CuListOffset = 24; uint32_t CuTypesOffset; - uint32_t SymTabOffset; + uint32_t SymtabOffset; uint32_t ConstantPoolOffset; uint32_t StringPoolOffset; + uint32_t StringPoolSize; - size_t CuVectorsSize = 0; - std::vector<size_t> CuVectorsOffset; - - bool Finalized = false; + std::vector<size_t> CuVectorOffsets; }; template <class ELFT> GdbIndexSection *createGdbIndex(); @@ -549,21 +584,12 @@ template <class ELFT> GdbIndexSection *createGdbIndex(); // Detailed info about internals can be found in Ian Lance Taylor's blog: // http://www.airs.com/blog/archives/460 (".eh_frame") // http://www.airs.com/blog/archives/462 (".eh_frame_hdr") -template <class ELFT> class EhFrameHeader final : public SyntheticSection { +class EhFrameHeader final : public SyntheticSection { public: EhFrameHeader(); void writeTo(uint8_t *Buf) override; size_t getSize() const override; - void addFde(uint32_t Pc, uint32_t FdeVA); bool empty() const override; - -private: - struct FdeData { - uint32_t Pc; - uint32_t FdeVA; - }; - - std::vector<FdeData> Fdes; }; // For more information about .gnu.version and .gnu.version_r see: @@ -639,22 +665,58 @@ public: // with different attributes in a single output sections. To do that // we put them into MergeSyntheticSection synthetic input sections which are // attached to regular output sections. -class MergeSyntheticSection final : public SyntheticSection { +class MergeSyntheticSection : public SyntheticSection { public: - MergeSyntheticSection(StringRef Name, uint32_t Type, uint64_t Flags, - uint32_t Alignment); void addSection(MergeInputSection *MS); + +protected: + MergeSyntheticSection(StringRef Name, uint32_t Type, uint64_t Flags, + uint32_t Alignment) + : SyntheticSection(Flags, Type, Alignment, Name) {} + + std::vector<MergeInputSection *> Sections; +}; + +class MergeTailSection final : public MergeSyntheticSection { +public: + MergeTailSection(StringRef Name, uint32_t Type, uint64_t Flags, + uint32_t Alignment); + + size_t getSize() const override; void writeTo(uint8_t *Buf) override; void finalizeContents() override; - bool shouldTailMerge() const; - size_t getSize() const override; private: - void finalizeTailMerge(); - void finalizeNoTailMerge(); - llvm::StringTableBuilder Builder; - std::vector<MergeInputSection *> Sections; +}; + +class MergeNoTailSection final : public MergeSyntheticSection { +public: + MergeNoTailSection(StringRef Name, uint32_t Type, uint64_t Flags, + uint32_t Alignment) + : MergeSyntheticSection(Name, Type, Flags, Alignment) {} + + size_t getSize() const override { return Size; } + void writeTo(uint8_t *Buf) override; + void finalizeContents() override; + +private: + // We use the most significant bits of a hash as a shard ID. + // The reason why we don't want to use the least significant bits is + // because DenseMap also uses lower bits to determine a bucket ID. + // If we use lower bits, it significantly increases the probability of + // hash collisons. + size_t getShardId(uint32_t Hash) { + return Hash >> (32 - llvm::countTrailingZeros(NumShards)); + } + + // Section size + size_t Size; + + // String table contents + constexpr static size_t NumShards = 32; + std::vector<llvm::StringTableBuilder> Shards; + size_t ShardOffsets[NumShards]; }; // .MIPS.abiflags section. @@ -746,13 +808,13 @@ private: size_t Size = 0; }; -template <class ELFT> InputSection *createCommonSection(); InputSection *createInterpSection(); template <class ELFT> MergeInputSection *createCommentSection(); -void decompressAndMergeSections(); +void decompressSections(); +void mergeSections(); -SymbolBody *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, - uint64_t Size, InputSectionBase *Section); +Symbol *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, + uint64_t Size, InputSectionBase *Section); // Linker generated sections which can be used as inputs. struct InX { @@ -760,11 +822,13 @@ struct InX { static BssSection *Bss; static BssSection *BssRelRo; static BuildIdSection *BuildId; - static InputSection *Common; + static EhFrameHeader *EhFrameHdr; + static EhFrameSection *EhFrame; static SyntheticSection *Dynamic; static StringTableSection *DynStrTab; static SymbolTableBaseSection *DynSymTab; static GnuHashTableSection *GnuHashTab; + static HashTableSection *HashTab; static InputSection *Interp; static GdbIndexSection *GdbIndex; static GotSection *Got; @@ -774,29 +838,20 @@ struct InX { static MipsRldMapSection *MipsRldMap; static PltSection *Plt; static PltSection *Iplt; + static RelocationBaseSection *RelaDyn; + static RelocationBaseSection *RelaPlt; + static RelocationBaseSection *RelaIplt; static StringTableSection *ShStrTab; static StringTableSection *StrTab; static SymbolTableBaseSection *SymTab; }; -template <class ELFT> struct In : public InX { - static EhFrameHeader<ELFT> *EhFrameHdr; - static EhFrameSection<ELFT> *EhFrame; - static HashTableSection<ELFT> *HashTab; - static RelocationSection<ELFT> *RelaDyn; - static RelocationSection<ELFT> *RelaPlt; - static RelocationSection<ELFT> *RelaIplt; +template <class ELFT> struct In { static VersionDefinitionSection<ELFT> *VerDef; static VersionTableSection<ELFT> *VerSym; static VersionNeedSection<ELFT> *VerNeed; }; -template <class ELFT> EhFrameHeader<ELFT> *In<ELFT>::EhFrameHdr; -template <class ELFT> EhFrameSection<ELFT> *In<ELFT>::EhFrame; -template <class ELFT> HashTableSection<ELFT> *In<ELFT>::HashTab; -template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaDyn; -template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaPlt; -template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaIplt; template <class ELFT> VersionDefinitionSection<ELFT> *In<ELFT>::VerDef; template <class ELFT> VersionTableSection<ELFT> *In<ELFT>::VerSym; template <class ELFT> VersionNeedSection<ELFT> *In<ELFT>::VerNeed; diff --git a/ELF/Target.cpp b/ELF/Target.cpp index 11986efc746f..ddd408906d14 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -25,11 +25,11 @@ //===----------------------------------------------------------------------===// #include "Target.h" -#include "Error.h" #include "InputFiles.h" #include "OutputSections.h" #include "SymbolTable.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" using namespace llvm; @@ -40,7 +40,7 @@ using namespace lld::elf; TargetInfo *elf::Target; -std::string lld::toString(uint32_t Type) { +std::string lld::toString(RelType Type) { StringRef S = getELFRelocationTypeName(elf::Config->EMachine, Type); if (S == "Unknown") return ("Unknown (" + Twine(Type) + ")").str(); @@ -117,27 +117,26 @@ std::string elf::getErrorLocation(const uint8_t *Loc) { TargetInfo::~TargetInfo() {} -int64_t TargetInfo::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { +int64_t TargetInfo::getImplicitAddend(const uint8_t *Buf, RelType Type) const { return 0; } -bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; } +bool TargetInfo::usesOnlyLowPageBits(RelType Type) const { return false; } -bool TargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType, - const InputFile *File, const SymbolBody &S) const { +bool TargetInfo::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const { return false; } -bool TargetInfo::inBranchRange(uint32_t RelocType, uint64_t Src, - uint64_t Dst) const { +bool TargetInfo::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { return true; } -void TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const { +void TargetInfo::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { writeGotPlt(Buf, S); } -RelExpr TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, +RelExpr TargetInfo::adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr Expr) const { return Expr; } @@ -146,22 +145,29 @@ void TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } -void TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, +void TargetInfo::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } -void TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, +void TargetInfo::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } -void TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, +void TargetInfo::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } -void TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, +void TargetInfo::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } + +uint64_t TargetInfo::getImageBase() { + // Use -image-base if set. Fall back to the target default if not. + if (Config->ImageBase) + return *Config->ImageBase; + return Config->Pic ? 0 : DefaultImageBase; +} diff --git a/ELF/Target.h b/ELF/Target.h index 1658a81c9b71..2902dbc99149 100644 --- a/ELF/Target.h +++ b/ELF/Target.h @@ -10,25 +10,27 @@ #ifndef LLD_ELF_TARGET_H #define LLD_ELF_TARGET_H -#include "Error.h" #include "InputSection.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" namespace lld { -std::string toString(uint32_t RelType); +std::string toString(elf::RelType Type); namespace elf { +class Defined; class InputFile; -class SymbolBody; +class Symbol; class TargetInfo { public: - virtual bool isPicRel(uint32_t Type) const { return true; } - virtual uint32_t getDynRel(uint32_t Type) const { return Type; } + virtual uint32_t calcEFlags() const { return 0; } + virtual bool isPicRel(RelType Type) const { return true; } + virtual RelType getDynRel(RelType Type) const { return Type; } virtual void writeGotPltHeader(uint8_t *Buf) const {} - virtual void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {}; - virtual void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const; - virtual int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const; + virtual void writeGotPlt(uint8_t *Buf, const Symbol &S) const {}; + virtual void writeIgotPlt(uint8_t *Buf, const Symbol &S) const; + virtual int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const; // If lazy binding is supported, the first entry of the PLT has code // to call the dynamic linker to resolve PLT entries the first time @@ -40,48 +42,52 @@ public: unsigned RelOff) const {} virtual void addPltHeaderSymbols(InputSectionBase *IS) const {} virtual void addPltSymbols(InputSectionBase *IS, uint64_t Off) const {} + // Returns true if a relocation only uses the low bits of a value such that // all those bits are in in the same page. For example, if the relocation // only uses the low 12 bits in a system with 4k pages. If this is true, the // bits will always have the same value at runtime and we don't have to emit // a dynamic relocation. - virtual bool usesOnlyLowPageBits(uint32_t Type) const; + virtual bool usesOnlyLowPageBits(RelType Type) const; // Decide whether a Thunk is needed for the relocation from File // targeting S. - virtual bool needsThunk(RelExpr Expr, uint32_t RelocType, - const InputFile *File, const SymbolBody &S) const; + virtual bool needsThunk(RelExpr Expr, RelType RelocType, + const InputFile *File, uint64_t BranchAddr, + const Symbol &S) const; // Return true if we can reach Dst from Src with Relocation RelocType - virtual bool inBranchRange(uint32_t RelocType, uint64_t Src, + virtual bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const; - virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + virtual RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const = 0; - virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0; + + virtual void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const = 0; + virtual ~TargetInfo(); unsigned TlsGdRelaxSkip = 1; unsigned PageSize = 4096; unsigned DefaultMaxPageSize = 4096; - // On FreeBSD x86_64 the first page cannot be mmaped. - // On Linux that is controled by vm.mmap_min_addr. At least on some x86_64 - // installs that is 65536, so the first 15 pages cannot be used. - // Given that, the smallest value that can be used in here is 0x10000. - uint64_t DefaultImageBase = 0x10000; + uint64_t getImageBase(); // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got section. Use -1 for // end of .got uint64_t GotBaseSymOff = 0; - uint32_t CopyRel; - uint32_t GotRel; - uint32_t PltRel; - uint32_t RelativeRel; - uint32_t IRelativeRel; - uint32_t TlsDescRel; - uint32_t TlsGotRel; - uint32_t TlsModuleIndexRel; - uint32_t TlsOffsetRel; + // On systems with range extensions we place collections of Thunks at + // regular spacings that enable the majority of branches reach the Thunks. + uint32_t ThunkSectionSpacing = 0; + + RelType CopyRel; + RelType GotRel; + RelType PltRel; + RelType RelativeRel; + RelType IRelativeRel; + RelType TlsDescRel; + RelType TlsGotRel; + RelType TlsModuleIndexRel; + RelType TlsOffsetRel; unsigned GotEntrySize = 0; unsigned GotPltEntrySize = 0; unsigned PltEntrySize; @@ -100,13 +106,20 @@ public: // executable OutputSections. uint32_t TrapInstr = 0; - virtual RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, + virtual RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, RelExpr Expr) const; virtual void relaxGot(uint8_t *Loc, uint64_t Val) const; - virtual void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; - virtual void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; - virtual void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; - virtual void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; + virtual void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const; + virtual void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const; + virtual void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const; + virtual void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const; + +protected: + // On FreeBSD x86_64 the first page cannot be mmaped. + // On Linux that is controled by vm.mmap_min_addr. At least on some x86_64 + // installs that is 65536, so the first 15 pages cannot be used. + // Given that, the smallest value that can be used in here is 0x10000. + uint64_t DefaultImageBase = 0x10000; }; TargetInfo *getAArch64TargetInfo(); @@ -129,32 +142,42 @@ uint64_t getAArch64Page(uint64_t Expr); extern TargetInfo *Target; TargetInfo *getTarget(); +template <class ELFT> bool isMipsPIC(const Defined *Sym); + +static inline void reportRangeError(uint8_t *Loc, RelType Type, const Twine &V, + int64_t Min, uint64_t Max) { + error(getErrorLocation(Loc) + "relocation " + lld::toString(Type) + + " out of range: " + V + " is not in [" + Twine(Min) + ", " + + Twine(Max) + "]"); +} + template <unsigned N> -static void checkInt(uint8_t *Loc, int64_t V, uint32_t Type) { +static void checkInt(uint8_t *Loc, int64_t V, RelType Type) { if (!llvm::isInt<N>(V)) - error(getErrorLocation(Loc) + "relocation " + lld::toString(Type) + - " out of range"); + reportRangeError(Loc, Type, Twine(V), llvm::minIntN(N), llvm::maxIntN(N)); } template <unsigned N> -static void checkUInt(uint8_t *Loc, uint64_t V, uint32_t Type) { +static void checkUInt(uint8_t *Loc, uint64_t V, RelType Type) { if (!llvm::isUInt<N>(V)) - error(getErrorLocation(Loc) + "relocation " + lld::toString(Type) + - " out of range"); + reportRangeError(Loc, Type, Twine(V), 0, llvm::maxUIntN(N)); } template <unsigned N> -static void checkIntUInt(uint8_t *Loc, uint64_t V, uint32_t Type) { +static void checkIntUInt(uint8_t *Loc, uint64_t V, RelType Type) { if (!llvm::isInt<N>(V) && !llvm::isUInt<N>(V)) - error(getErrorLocation(Loc) + "relocation " + lld::toString(Type) + - " out of range"); + // For the error message we should cast V to a signed integer so that error + // messages show a small negative value rather than an extremely large one + reportRangeError(Loc, Type, Twine((int64_t)V), llvm::minIntN(N), + llvm::maxUIntN(N)); } template <unsigned N> -static void checkAlignment(uint8_t *Loc, uint64_t V, uint32_t Type) { +static void checkAlignment(uint8_t *Loc, uint64_t V, RelType Type) { if ((V & (N - 1)) != 0) error(getErrorLocation(Loc) + "improper alignment for relocation " + - lld::toString(Type)); + lld::toString(Type) + ": 0x" + llvm::utohexstr(V) + + " is not aligned to " + Twine(N) + " bytes"); } } // namespace elf } // namespace lld diff --git a/ELF/Threads.h b/ELF/Threads.h deleted file mode 100644 index 9feb8683976c..000000000000 --- a/ELF/Threads.h +++ /dev/null @@ -1,88 +0,0 @@ -//===- Threads.h ------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// LLD supports threads to distribute workloads to multiple cores. Using -// multicore is most effective when more than one core are idle. At the -// last step of a build, it is often the case that a linker is the only -// active process on a computer. So, we are naturally interested in using -// threads wisely to reduce latency to deliver results to users. -// -// That said, we don't want to do "too clever" things using threads. -// Complex multi-threaded algorithms are sometimes extremely hard to -// reason about and can easily mess up the entire design. -// -// Fortunately, when a linker links large programs (when the link time is -// most critical), it spends most of the time to work on massive number of -// small pieces of data of the same kind, and there are opportunities for -// large parallelism there. Here are examples: -// -// - We have hundreds of thousands of input sections that need to be -// copied to a result file at the last step of link. Once we fix a file -// layout, each section can be copied to its destination and its -// relocations can be applied independently. -// -// - We have tens of millions of small strings when constructing a -// mergeable string section. -// -// For the cases such as the former, we can just use parallel_for_each -// instead of std::for_each (or a plain for loop). Because tasks are -// completely independent from each other, we can run them in parallel -// without any coordination between them. That's very easy to understand -// and reason about. -// -// For the cases such as the latter, we can use parallel algorithms to -// deal with massive data. We have to write code for a tailored algorithm -// for each problem, but the complexity of multi-threading is isolated in -// a single pass and doesn't affect the linker's overall design. -// -// The above approach seems to be working fairly well. As an example, when -// linking Chromium (output size 1.6 GB), using 4 cores reduces latency to -// 75% compared to single core (from 12.66 seconds to 9.55 seconds) on my -// Ivy Bridge Xeon 2.8 GHz machine. Using 40 cores reduces it to 63% (from -// 12.66 seconds to 7.95 seconds). Because of the Amdahl's law, the -// speedup is not linear, but as you add more cores, it gets faster. -// -// On a final note, if you are trying to optimize, keep the axiom "don't -// guess, measure!" in mind. Some important passes of the linker are not -// that slow. For example, resolving all symbols is not a very heavy pass, -// although it would be very hard to parallelize it. You want to first -// identify a slow pass and then optimize it. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_ELF_THREADS_H -#define LLD_ELF_THREADS_H - -#include "Config.h" - -#include "llvm/Support/Parallel.h" -#include <functional> - -namespace lld { -namespace elf { - -template <class IterTy, class FuncTy> -void parallelForEach(IterTy Begin, IterTy End, FuncTy Fn) { - if (Config->Threads) - for_each(llvm::parallel::par, Begin, End, Fn); - else - for_each(llvm::parallel::seq, Begin, End, Fn); -} - -inline void parallelForEachN(size_t Begin, size_t End, - std::function<void(size_t)> Fn) { - if (Config->Threads) - for_each_n(llvm::parallel::par, Begin, End, Fn); - else - for_each_n(llvm::parallel::seq, Begin, End, Fn); -} -} // namespace elf -} // namespace lld - -#endif diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp index 07289d0efdf1..91ca3b9b5bc2 100644 --- a/ELF/Thunks.cpp +++ b/ELF/Thunks.cpp @@ -23,13 +23,13 @@ #include "Thunks.h" #include "Config.h" -#include "Error.h" #include "InputSection.h" -#include "Memory.h" #include "OutputSections.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Endian.h" @@ -48,52 +48,69 @@ namespace elf { namespace { +// AArch64 long range Thunks +class AArch64ABSLongThunk final : public Thunk { +public: + AArch64ABSLongThunk(Symbol &Dest) : Thunk(Dest) {} + uint32_t size() const override { return 16; } + void writeTo(uint8_t *Buf, ThunkSection &IS) const override; + void addSymbols(ThunkSection &IS) override; +}; + +class AArch64ADRPThunk final : public Thunk { +public: + AArch64ADRPThunk(Symbol &Dest) : Thunk(Dest) {} + uint32_t size() const override { return 12; } + void writeTo(uint8_t *Buf, ThunkSection &IS) const override; + void addSymbols(ThunkSection &IS) override; +}; + // Specific ARM Thunk implementations. The naming convention is: // Source State, TargetState, Target Requirement, ABS or PI, Range class ARMV7ABSLongThunk final : public Thunk { public: - ARMV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) {} + ARMV7ABSLongThunk(Symbol &Dest) : Thunk(Dest) {} uint32_t size() const override { return 12; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; - bool isCompatibleWith(uint32_t RelocType) const override; + bool isCompatibleWith(RelType Type) const override; }; class ARMV7PILongThunk final : public Thunk { public: - ARMV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) {} + ARMV7PILongThunk(Symbol &Dest) : Thunk(Dest) {} uint32_t size() const override { return 16; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; - bool isCompatibleWith(uint32_t RelocType) const override; + bool isCompatibleWith(RelType Type) const override; }; class ThumbV7ABSLongThunk final : public Thunk { public: - ThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) { Alignment = 2; } + ThumbV7ABSLongThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; } uint32_t size() const override { return 10; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; - bool isCompatibleWith(uint32_t RelocType) const override; + bool isCompatibleWith(RelType Type) const override; }; class ThumbV7PILongThunk final : public Thunk { public: - ThumbV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) { Alignment = 2; } + ThumbV7PILongThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; } uint32_t size() const override { return 12; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; - bool isCompatibleWith(uint32_t RelocType) const override; + bool isCompatibleWith(RelType Type) const override; }; // MIPS LA25 thunk class MipsThunk final : public Thunk { public: - MipsThunk(const SymbolBody &Dest) : Thunk(Dest) {} + MipsThunk(Symbol &Dest) : Thunk(Dest) {} uint32_t size() const override { return 16; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; @@ -101,10 +118,86 @@ public: InputSection *getTargetInputSection() const override; }; +// microMIPS R2-R5 LA25 thunk +class MicroMipsThunk final : public Thunk { +public: + MicroMipsThunk(Symbol &Dest) : Thunk(Dest) {} + + uint32_t size() const override { return 14; } + void writeTo(uint8_t *Buf, ThunkSection &IS) const override; + void addSymbols(ThunkSection &IS) override; + InputSection *getTargetInputSection() const override; +}; + +// microMIPS R6 LA25 thunk +class MicroMipsR6Thunk final : public Thunk { +public: + MicroMipsR6Thunk(Symbol &Dest) : Thunk(Dest) {} + + uint32_t size() const override { return 12; } + void writeTo(uint8_t *Buf, ThunkSection &IS) const override; + void addSymbols(ThunkSection &IS) override; + InputSection *getTargetInputSection() const override; +}; + } // end anonymous namespace +// AArch64 long range Thunks + +static uint64_t getAArch64ThunkDestVA(const Symbol &S) { + uint64_t V = S.isInPlt() ? S.getPltVA() : S.getVA(); + return V; +} + +void AArch64ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { + const uint8_t Data[] = { + 0x50, 0x00, 0x00, 0x58, // ldr x16, L0 + 0x00, 0x02, 0x1f, 0xd6, // br x16 + 0x00, 0x00, 0x00, 0x00, // L0: .xword S + 0x00, 0x00, 0x00, 0x00, + }; + uint64_t S = getAArch64ThunkDestVA(Destination); + memcpy(Buf, Data, sizeof(Data)); + Target->relocateOne(Buf + 8, R_AARCH64_ABS64, S); +} + +void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) { + ThunkSym = addSyntheticLocal( + Saver.save("__AArch64AbsLongThunk_" + Destination.getName()), STT_FUNC, + Offset, size(), &IS); + addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, &IS); + addSyntheticLocal("$d", STT_NOTYPE, Offset + 8, 0, &IS); +} + +// This Thunk has a maximum range of 4Gb, this is sufficient for all programs +// using the small code model, including pc-relative ones. At time of writing +// clang and gcc do not support the large code model for position independent +// code so it is safe to use this for position independent thunks without +// worrying about the destination being more than 4Gb away. +void AArch64ADRPThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { + const uint8_t Data[] = { + 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest) + 0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest) + 0x00, 0x02, 0x1f, 0xd6, // br x16 + }; + uint64_t S = getAArch64ThunkDestVA(Destination); + uint64_t P = ThunkSym->getVA(); + memcpy(Buf, Data, sizeof(Data)); + Target->relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, + getAArch64Page(S) - getAArch64Page(P)); + Target->relocateOne(Buf + 4, R_AARCH64_ADD_ABS_LO12_NC, S); +} + +void AArch64ADRPThunk::addSymbols(ThunkSection &IS) +{ + ThunkSym = addSyntheticLocal( + Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC, + Offset, size(), &IS); + addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, &IS); +} + // ARM Target Thunks -static uint64_t getARMThunkDestVA(const SymbolBody &S) { +static uint64_t getARMThunkDestVA(const Symbol &S) { uint64_t V = S.isInPlt() ? S.getPltVA() : S.getVA(); return SignExtend64<32>(V); } @@ -128,9 +221,9 @@ void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS); } -bool ARMV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { +bool ARMV7ABSLongThunk::isCompatibleWith(RelType Type) const { // Thumb branch relocations can't use BLX - return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; + return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24; } void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { @@ -152,24 +245,24 @@ void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); } -bool ThumbV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { +bool ThumbV7ABSLongThunk::isCompatibleWith(RelType Type) const { // ARM branch relocations can't use BLX - return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 && - RelocType != R_ARM_PLT32; + return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32; } void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { - 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) +8) - 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P+4) +8) + 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) + 8) + 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P) + 8) 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc 0x1c, 0xff, 0x2f, 0xe1, // bx r12 }; uint64_t S = getARMThunkDestVA(Destination); uint64_t P = ThunkSym->getVA(); + uint64_t Offset = S - P - 16; memcpy(Buf, Data, sizeof(Data)); - Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, S - P - 16); - Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, S - P - 12); + Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, Offset); + Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, Offset); } void ARMV7PILongThunk::addSymbols(ThunkSection &IS) { @@ -179,23 +272,24 @@ void ARMV7PILongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS); } -bool ARMV7PILongThunk::isCompatibleWith(uint32_t RelocType) const { +bool ARMV7PILongThunk::isCompatibleWith(RelType Type) const { // Thumb branch relocations can't use BLX - return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; + return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24; } void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4) - 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P+4) + 4) + 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4) 0xfc, 0x44, // L1: add r12, pc 0x60, 0x47, // bx r12 }; uint64_t S = getARMThunkDestVA(Destination); uint64_t P = ThunkSym->getVA() & ~0x1; + uint64_t Offset = S - P - 12; memcpy(Buf, Data, sizeof(Data)); - Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, S - P - 12); - Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, S - P - 8); + Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, Offset); + Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, Offset); } void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) { @@ -205,10 +299,9 @@ void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); } -bool ThumbV7PILongThunk::isCompatibleWith(uint32_t RelocType) const { +bool ThumbV7PILongThunk::isCompatibleWith(RelType Type) const { // ARM branch relocations can't use BLX - return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 && - RelocType != R_ARM_PLT32; + return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32; } // Write MIPS LA25 thunk code to call PIC function from the non-PIC one. @@ -229,16 +322,74 @@ void MipsThunk::addSymbols(ThunkSection &IS) { } InputSection *MipsThunk::getTargetInputSection() const { - auto *DR = dyn_cast<DefinedRegular>(&Destination); - return dyn_cast<InputSection>(DR->Section); + auto &DR = cast<Defined>(Destination); + return dyn_cast<InputSection>(DR.Section); } -Thunk::Thunk(const SymbolBody &D) : Destination(D), Offset(0) {} +// Write microMIPS R2-R5 LA25 thunk code +// to call PIC function from the non-PIC one. +void MicroMipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const { + uint64_t S = Destination.getVA() | 1; + write16(Buf, 0x41b9, Config->Endianness); // lui $25, %hi(func) + write16(Buf + 4, 0xd400, Config->Endianness); // j func + write16(Buf + 8, 0x3339, Config->Endianness); // addiu $25, $25, %lo(func) + write16(Buf + 12, 0x0c00, Config->Endianness); // nop + Target->relocateOne(Buf, R_MICROMIPS_HI16, S); + Target->relocateOne(Buf + 4, R_MICROMIPS_26_S1, S); + Target->relocateOne(Buf + 8, R_MICROMIPS_LO16, S); +} + +void MicroMipsThunk::addSymbols(ThunkSection &IS) { + ThunkSym = + addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()), + STT_FUNC, Offset, size(), &IS); + ThunkSym->StOther |= STO_MIPS_MICROMIPS; +} + +InputSection *MicroMipsThunk::getTargetInputSection() const { + auto &DR = cast<Defined>(Destination); + return dyn_cast<InputSection>(DR.Section); +} + +// Write microMIPS R6 LA25 thunk code +// to call PIC function from the non-PIC one. +void MicroMipsR6Thunk::writeTo(uint8_t *Buf, ThunkSection &) const { + uint64_t S = Destination.getVA() | 1; + uint64_t P = ThunkSym->getVA(); + write16(Buf, 0x1320, Config->Endianness); // lui $25, %hi(func) + write16(Buf + 4, 0x3339, Config->Endianness); // addiu $25, $25, %lo(func) + write16(Buf + 8, 0x9400, Config->Endianness); // bc func + Target->relocateOne(Buf, R_MICROMIPS_HI16, S); + Target->relocateOne(Buf + 4, R_MICROMIPS_LO16, S); + Target->relocateOne(Buf + 8, R_MICROMIPS_PC26_S1, S - P - 12); +} + +void MicroMipsR6Thunk::addSymbols(ThunkSection &IS) { + ThunkSym = + addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()), + STT_FUNC, Offset, size(), &IS); + ThunkSym->StOther |= STO_MIPS_MICROMIPS; +} + +InputSection *MicroMipsR6Thunk::getTargetInputSection() const { + auto &DR = cast<Defined>(Destination); + return dyn_cast<InputSection>(DR.Section); +} + +Thunk::Thunk(Symbol &D) : Destination(D), Offset(0) {} Thunk::~Thunk() = default; +static Thunk *addThunkAArch64(RelType Type, Symbol &S) { + if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26) + fatal("unrecognized relocation type"); + if (Config->Pic) + return make<AArch64ADRPThunk>(S); + return make<AArch64ABSLongThunk>(S); +} + // Creates a thunk for Thumb-ARM interworking. -static Thunk *addThunkArm(uint32_t Reloc, SymbolBody &S) { +static Thunk *addThunkArm(RelType Reloc, Symbol &S) { // ARM relocations need ARM to Thumb interworking Thunks. // Thumb relocations need Thumb to ARM relocations. // Use position independent Thunks if we require position independent code. @@ -246,11 +397,13 @@ static Thunk *addThunkArm(uint32_t Reloc, SymbolBody &S) { case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_JUMP24: + case R_ARM_CALL: if (Config->Pic) return make<ARMV7PILongThunk>(S); return make<ARMV7ABSLongThunk>(S); case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: + case R_ARM_THM_CALL: if (Config->Pic) return make<ThumbV7PILongThunk>(S); return make<ThumbV7ABSLongThunk>(S); @@ -258,13 +411,21 @@ static Thunk *addThunkArm(uint32_t Reloc, SymbolBody &S) { fatal("unrecognized relocation type"); } -static Thunk *addThunkMips(SymbolBody &S) { return make<MipsThunk>(S); } +static Thunk *addThunkMips(RelType Type, Symbol &S) { + if ((S.StOther & STO_MIPS_MICROMIPS) && isMipsR6()) + return make<MicroMipsR6Thunk>(S); + if (S.StOther & STO_MIPS_MICROMIPS) + return make<MicroMipsThunk>(S); + return make<MipsThunk>(S); +} -Thunk *addThunk(uint32_t RelocType, SymbolBody &S) { - if (Config->EMachine == EM_ARM) - return addThunkArm(RelocType, S); +Thunk *addThunk(RelType Type, Symbol &S) { + if (Config->EMachine == EM_AARCH64) + return addThunkAArch64(Type, S); + else if (Config->EMachine == EM_ARM) + return addThunkArm(Type, S); else if (Config->EMachine == EM_MIPS) - return addThunkMips(S); + return addThunkMips(Type, S); llvm_unreachable("add Thunk only supported for ARM and Mips"); return nullptr; } diff --git a/ELF/Thunks.h b/ELF/Thunks.h index 21eba699fe4f..828fac0bf53b 100644 --- a/ELF/Thunks.h +++ b/ELF/Thunks.h @@ -14,7 +14,7 @@ namespace lld { namespace elf { -class SymbolBody; +class Symbol; class ThunkSection; // Class to describe an instance of a Thunk. // A Thunk is a code-sequence inserted by the linker in between a caller and @@ -23,11 +23,11 @@ class ThunkSection; // include transferring control from non-pi to pi and changing state on // targets like ARM. // -// Thunks can be created for DefinedRegular, Shared and Undefined Symbols. +// Thunks can be created for Defined, Shared and Undefined Symbols. // Thunks are assigned to synthetic ThunkSections class Thunk { public: - Thunk(const SymbolBody &Destination); + Thunk(Symbol &Destination); virtual ~Thunk(); virtual uint32_t size() const { return 0; } @@ -41,21 +41,21 @@ public: // a branch and fall through to the first Symbol in the Target. virtual InputSection *getTargetInputSection() const { return nullptr; } - // To reuse a Thunk the caller as identified by the RelocType must be + // To reuse a Thunk the caller as identified by the Type must be // compatible with it. - virtual bool isCompatibleWith(uint32_t RelocType) const { return true; } + virtual bool isCompatibleWith(RelType Type) const { return true; } // The alignment requirement for this Thunk, defaults to the size of the // typical code section alignment. - const SymbolBody &Destination; - SymbolBody *ThunkSym; - uint64_t Offset; + Symbol &Destination; + Symbol *ThunkSym; + uint64_t Offset = 0; uint32_t Alignment = 4; }; // For a Relocation to symbol S create a Thunk to be added to a synthetic // ThunkSection. At present there are implementations for ARM and Mips Thunks. -Thunk *addThunk(uint32_t RelocType, SymbolBody &S); +Thunk *addThunk(RelType Type, Symbol &S); } // namespace elf } // namespace lld diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 1853f99bc600..c7a3cae49ae6 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -8,22 +8,22 @@ //===----------------------------------------------------------------------===// #include "Writer.h" +#include "AArch64ErrataFix.h" #include "Config.h" #include "Filesystem.h" #include "LinkerScript.h" #include "MapFile.h" -#include "Memory.h" #include "OutputSections.h" #include "Relocations.h" #include "Strings.h" #include "SymbolTable.h" +#include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" -#include "Threads.h" +#include "lld/Common/Memory.h" +#include "lld/Common/Threads.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/raw_ostream.h" #include <climits> using namespace llvm; @@ -39,6 +39,7 @@ namespace { // The writer writes a SymbolTable result to a file. template <class ELFT> class Writer { public: + Writer() : Buffer(errorHandler().OutputBuffer) {} typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Ehdr Elf_Ehdr; typedef typename ELFT::Phdr Elf_Phdr; @@ -46,43 +47,38 @@ public: void run(); private: - void clearOutputSections(); - void createSyntheticSections(); void copyLocalSymbols(); void addSectionSymbols(); - void addReservedSymbols(); - void createSections(); void forEachRelSec(std::function<void(InputSectionBase &)> Fn); void sortSections(); + void resolveShfLinkOrder(); + void sortInputSections(); void finalizeSections(); void addPredefinedSections(); + void setReservedSymbolSections(); - std::vector<PhdrEntry> createPhdrs(); + std::vector<PhdrEntry *> createPhdrs(); void removeEmptyPTLoad(); - void addPtArmExid(std::vector<PhdrEntry> &Phdrs); + void addPtArmExid(std::vector<PhdrEntry *> &Phdrs); void assignFileOffsets(); void assignFileOffsetsBinary(); void setPhdrs(); void fixSectionAlignments(); - void fixPredefinedSymbols(); void openFile(); + void writeTrapInstr(); void writeHeader(); void writeSections(); void writeSectionsBinary(); void writeBuildId(); - std::unique_ptr<FileOutputBuffer> Buffer; - - OutputSectionFactory Factory; + std::unique_ptr<FileOutputBuffer> &Buffer; void addRelIpltSymbols(); void addStartEndSymbols(); void addStartStopSymbols(OutputSection *Sec); uint64_t getEntryAddr(); - OutputSection *findSectionInScript(StringRef Name); - OutputSectionCommand *findSectionCommand(StringRef Name); - std::vector<PhdrEntry> Phdrs; + std::vector<PhdrEntry *> Phdrs; uint64_t FileSize; uint64_t SectionHeaderOff; @@ -91,49 +87,60 @@ private: }; } // anonymous namespace -StringRef elf::getOutputSectionName(StringRef Name) { +StringRef elf::getOutputSectionName(InputSectionBase *S) { // ".zdebug_" is a prefix for ZLIB-compressed sections. // Because we decompressed input sections, we want to remove 'z'. - if (Name.startswith(".zdebug_")) - return Saver.save("." + Name.substr(2)); + if (S->Name.startswith(".zdebug_")) + return Saver.save("." + S->Name.substr(2)); if (Config->Relocatable) - return Name; + return S->Name; + + // This is for --emit-relocs. If .text.foo is emitted as .text.bar, we want + // to emit .rela.text.foo as .rela.text.bar for consistency (this is not + // technically required, but not doing it is odd). This code guarantees that. + if ((S->Type == SHT_REL || S->Type == SHT_RELA) && + !isa<SyntheticSection>(S)) { + OutputSection *Out = + cast<InputSection>(S)->getRelocatedSection()->getOutputSection(); + if (S->Type == SHT_RELA) + return Saver.save(".rela" + Out->Name); + return Saver.save(".rel" + Out->Name); + } for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.", ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."}) { StringRef Prefix = V.drop_back(); - if (Name.startswith(V) || Name == Prefix) + if (S->Name.startswith(V) || S->Name == Prefix) return Prefix; } // CommonSection is identified as "COMMON" in linker scripts. // By default, it should go to .bss section. - if (Name == "COMMON") + if (S->Name == "COMMON") return ".bss"; - return Name; + return S->Name; } -template <class ELFT> static bool needsInterpSection() { - return !Symtab<ELFT>::X->getSharedFiles().empty() && - !Config->DynamicLinker.empty() && !Script->ignoreInterpSection(); +static bool needsInterpSection() { + return !SharedFiles.empty() && !Config->DynamicLinker.empty() && + Script->needsInterpSection(); } template <class ELFT> void elf::writeResult() { Writer<ELFT>().run(); } template <class ELFT> void Writer<ELFT>::removeEmptyPTLoad() { - auto I = std::remove_if(Phdrs.begin(), Phdrs.end(), [&](const PhdrEntry &P) { - if (P.p_type != PT_LOAD) + llvm::erase_if(Phdrs, [&](const PhdrEntry *P) { + if (P->p_type != PT_LOAD) return false; - if (!P.First) + if (!P->FirstSec) return true; - uint64_t Size = P.Last->Addr + P.Last->Size - P.First->Addr; + uint64_t Size = P->LastSec->Addr + P->LastSec->Size - P->FirstSec->Addr; return Size == 0; }); - Phdrs.erase(I, Phdrs.end()); } template <class ELFT> static void combineEhFrameSections() { @@ -142,7 +149,7 @@ template <class ELFT> static void combineEhFrameSections() { if (!ES || !ES->Live) continue; - In<ELFT>::EhFrame->addSection(ES); + InX::EhFrame->addSection<ELFT>(ES); S = nullptr; } @@ -150,130 +157,88 @@ template <class ELFT> static void combineEhFrameSections() { V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); } -template <class ELFT> void Writer<ELFT>::clearOutputSections() { - // Clear the OutputSections to make sure it is not used anymore. Any - // code from this point on should be using the linker script - // commands. - for (OutputSection *Sec : OutputSections) - Sec->Sections.clear(); - OutputSections.clear(); +template <class ELFT> +static Defined *addOptionalRegular(StringRef Name, SectionBase *Sec, + uint64_t Val, uint8_t StOther = STV_HIDDEN, + uint8_t Binding = STB_GLOBAL) { + Symbol *S = Symtab->find(Name); + if (!S || S->isDefined()) + return nullptr; + Symbol *Sym = Symtab->addRegular<ELFT>(Name, StOther, STT_NOTYPE, Val, + /*Size=*/0, Binding, Sec, + /*File=*/nullptr); + return cast<Defined>(Sym); } -// The main function of the writer. -template <class ELFT> void Writer<ELFT>::run() { - // Create linker-synthesized sections such as .got or .plt. - // Such sections are of type input section. - createSyntheticSections(); - - if (!Config->Relocatable) - combineEhFrameSections<ELFT>(); - - // We need to create some reserved symbols such as _end. Create them. - if (!Config->Relocatable) - addReservedSymbols(); - - // Create output sections. - if (Script->Opt.HasSections) { - // If linker script contains SECTIONS commands, let it create sections. - Script->processCommands(Factory); - - // Linker scripts may have left some input sections unassigned. - // Assign such sections using the default rule. - Script->addOrphanSections(Factory); - } else { - // If linker script does not contain SECTIONS commands, create - // output sections by default rules. We still need to give the - // linker script a chance to run, because it might contain - // non-SECTIONS commands such as ASSERT. - Script->processCommands(Factory); - createSections(); - } - clearOutputSections(); - - if (Config->Discard != DiscardPolicy::All) - copyLocalSymbols(); - - if (Config->CopyRelocs) - addSectionSymbols(); - - // Now that we have a complete set of output sections. This function - // completes section contents. For example, we need to add strings - // to the string table, and add entries to .got and .plt. - // finalizeSections does that. - finalizeSections(); - if (ErrorCount) - return; - - if (!Script->Opt.HasSections && !Config->Relocatable) - fixSectionAlignments(); - - // If -compressed-debug-sections is specified, we need to compress - // .debug_* sections. Do it right now because it changes the size of - // output sections. - parallelForEach( - OutputSectionCommands.begin(), OutputSectionCommands.end(), - [](OutputSectionCommand *Cmd) { Cmd->maybeCompress<ELFT>(); }); - - Script->assignAddresses(); - Script->allocateHeaders(Phdrs); - - // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a - // 0 sized region. This has to be done late since only after assignAddresses - // we know the size of the sections. - removeEmptyPTLoad(); - - if (!Config->OFormatBinary) - assignFileOffsets(); - else - assignFileOffsetsBinary(); +// The linker is expected to define some symbols depending on +// the linking result. This function defines such symbols. +template <class ELFT> void elf::addReservedSymbols() { + if (Config->EMachine == EM_MIPS) { + // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer + // so that it points to an absolute address which by default is relative + // to GOT. Default offset is 0x7ff0. + // See "Global Data Symbols" in Chapter 6 in the following document: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + ElfSym::MipsGp = Symtab->addAbsolute<ELFT>("_gp", STV_HIDDEN, STB_GLOBAL); - setPhdrs(); + // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between + // start of function and 'gp' pointer into GOT. + if (Symtab->find("_gp_disp")) + ElfSym::MipsGpDisp = + Symtab->addAbsolute<ELFT>("_gp_disp", STV_HIDDEN, STB_GLOBAL); - if (Config->Relocatable) { - for (OutputSectionCommand *Cmd : OutputSectionCommands) - Cmd->Sec->Addr = 0; - } else { - fixPredefinedSymbols(); + // The __gnu_local_gp is a magic symbol equal to the current value of 'gp' + // pointer. This symbol is used in the code generated by .cpload pseudo-op + // in case of using -mno-shared option. + // https://sourceware.org/ml/binutils/2004-12/msg00094.html + if (Symtab->find("__gnu_local_gp")) + ElfSym::MipsLocalGp = + Symtab->addAbsolute<ELFT>("__gnu_local_gp", STV_HIDDEN, STB_GLOBAL); } - // It does not make sense try to open the file if we have error already. - if (ErrorCount) - return; - // Write the result down to a file. - openFile(); - if (ErrorCount) - return; + ElfSym::GlobalOffsetTable = addOptionalRegular<ELFT>( + "_GLOBAL_OFFSET_TABLE_", Out::ElfHeader, Target->GotBaseSymOff); - if (!Config->OFormatBinary) { - writeHeader(); - writeSections(); - } else { - writeSectionsBinary(); - } + // __ehdr_start is the location of ELF file headers. Note that we define + // this symbol unconditionally even when using a linker script, which + // differs from the behavior implemented by GNU linker which only define + // this symbol if ELF headers are in the memory mapped segment. + // __executable_start is not documented, but the expectation of at + // least the android libc is that it points to the elf header too. + // __dso_handle symbol is passed to cxa_finalize as a marker to identify + // each DSO. The address of the symbol doesn't matter as long as they are + // different in different DSOs, so we chose the start address of the DSO. + for (const char *Name : + {"__ehdr_start", "__executable_start", "__dso_handle"}) + addOptionalRegular<ELFT>(Name, Out::ElfHeader, 0, STV_HIDDEN); - // Backfill .note.gnu.build-id section content. This is done at last - // because the content is usually a hash value of the entire output file. - writeBuildId(); - if (ErrorCount) + // If linker script do layout we do not need to create any standart symbols. + if (Script->HasSectionsCommand) return; - // Handle -Map option. - writeMapFile<ELFT>(OutputSectionCommands); - if (ErrorCount) - return; + auto Add = [](StringRef S, int64_t Pos) { + return addOptionalRegular<ELFT>(S, Out::ElfHeader, Pos, STV_DEFAULT); + }; - if (auto EC = Buffer->commit()) - error("failed to write to the output file: " + EC.message()); + ElfSym::Bss = Add("__bss_start", 0); + ElfSym::End1 = Add("end", -1); + ElfSym::End2 = Add("_end", -1); + ElfSym::Etext1 = Add("etext", -1); + ElfSym::Etext2 = Add("_etext", -1); + ElfSym::Edata1 = Add("edata", -1); + ElfSym::Edata2 = Add("_edata", -1); +} - // Flush the output streams and exit immediately. A full shutdown - // is a good test that we are keeping track of all allocated memory, - // but actually freeing it is a waste of time in a regular linker run. - if (Config->ExitEarly) - exitLld(0); +static OutputSection *findSection(StringRef Name) { + for (BaseCommand *Base : Script->SectionCommands) + if (auto *Sec = dyn_cast<OutputSection>(Base)) + if (Sec->Name == Name) + return Sec; + return nullptr; } // Initialize Out members. -template <class ELFT> void Writer<ELFT>::createSyntheticSections() { +template <class ELFT> static void createSyntheticSections() { // Initialize all pointers with NULL. This is needed because // you can call lld::elf::main more than once as a library. memset(&Out::First, 0, sizeof(Out)); @@ -282,16 +247,19 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() { InX::DynStrTab = make<StringTableSection>(".dynstr", true); InX::Dynamic = make<DynamicSection<ELFT>>(); - In<ELFT>::RelaDyn = make<RelocationSection<ELFT>>( - Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); + if (Config->AndroidPackDynRelocs) { + InX::RelaDyn = make<AndroidPackedRelocationSection<ELFT>>( + Config->IsRela ? ".rela.dyn" : ".rel.dyn"); + } else { + InX::RelaDyn = make<RelocationSection<ELFT>>( + Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); + } InX::ShStrTab = make<StringTableSection>(".shstrtab", false); - Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC); - Out::ElfHeader->Size = sizeof(Elf_Ehdr); Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC); - Out::ProgramHeaders->updateAlignment(Config->Wordsize); + Out::ProgramHeaders->Alignment = Config->Wordsize; - if (needsInterpSection<ELFT>()) { + if (needsInterpSection()) { InX::Interp = createInterpSection(); Add(InX::Interp); } else { @@ -308,20 +276,21 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() { Add(InX::BuildId); } - InX::Common = createCommonSection<ELFT>(); - if (InX::Common) - Add(InX::Common); - - InX::Bss = make<BssSection>(".bss"); + InX::Bss = make<BssSection>(".bss", 0, 1); Add(InX::Bss); - InX::BssRelRo = make<BssSection>(".bss.rel.ro"); + + // If there is a SECTIONS command and a .data.rel.ro section name use name + // .data.rel.ro.bss so that we match in the .data.rel.ro output section. + // This makes sure our relro is contiguous. + bool HasDataRelRo = + Script->HasSectionsCommand && findSection(".data.rel.ro"); + InX::BssRelRo = make<BssSection>( + HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1); Add(InX::BssRelRo); // Add MIPS-specific sections. - bool HasDynSymTab = !Symtab<ELFT>::X->getSharedFiles().empty() || - Config->Pic || Config->ExportDynamic; if (Config->EMachine == EM_MIPS) { - if (!Config->Shared && HasDynSymTab) { + if (!Config->Shared && Config->HasDynSymTab) { InX::MipsRldMap = make<MipsRldMapSection>(); Add(InX::MipsRldMap); } @@ -333,7 +302,7 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() { Add(Sec); } - if (HasDynSymTab) { + if (Config->HasDynSymTab) { InX::DynSymTab = make<SymbolTableSection<ELFT>>(*InX::DynStrTab); Add(InX::DynSymTab); @@ -354,13 +323,13 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() { } if (Config->SysvHash) { - In<ELFT>::HashTab = make<HashTableSection<ELFT>>(); - Add(In<ELFT>::HashTab); + InX::HashTab = make<HashTableSection>(); + Add(InX::HashTab); } Add(InX::Dynamic); Add(InX::DynStrTab); - Add(In<ELFT>::RelaDyn); + Add(InX::RelaDyn); } // Add .got. MIPS' .got is so different from the other archs, @@ -385,16 +354,22 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() { // We always need to add rel[a].plt to output if it has entries. // Even for static linking it can contain R_[*]_IRELATIVE relocations. - In<ELFT>::RelaPlt = make<RelocationSection<ELFT>>( + InX::RelaPlt = make<RelocationSection<ELFT>>( Config->IsRela ? ".rela.plt" : ".rel.plt", false /*Sort*/); - Add(In<ELFT>::RelaPlt); + Add(InX::RelaPlt); // The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure - // that the IRelative relocations are processed last by the dynamic loader - In<ELFT>::RelaIplt = make<RelocationSection<ELFT>>( - (Config->EMachine == EM_ARM) ? ".rel.dyn" : In<ELFT>::RelaPlt->Name, + // that the IRelative relocations are processed last by the dynamic loader. + // We cannot place the iplt section in .rel.dyn when Android relocation + // packing is enabled because that would cause a section type mismatch. + // However, because the Android dynamic loader reads .rel.plt after .rel.dyn, + // we can get the desired behaviour by placing the iplt section in .rel.plt. + InX::RelaIplt = make<RelocationSection<ELFT>>( + (Config->EMachine == EM_ARM && !Config->AndroidPackDynRelocs) + ? ".rel.dyn" + : InX::RelaPlt->Name, false /*Sort*/); - Add(In<ELFT>::RelaIplt); + Add(InX::RelaIplt); InX::Plt = make<PltSection>(Target->PltHeaderSize); Add(InX::Plt); @@ -403,11 +378,11 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() { if (!Config->Relocatable) { if (Config->EhFrameHdr) { - In<ELFT>::EhFrameHdr = make<EhFrameHeader<ELFT>>(); - Add(In<ELFT>::EhFrameHdr); + InX::EhFrameHdr = make<EhFrameHeader>(); + Add(InX::EhFrameHdr); } - In<ELFT>::EhFrame = make<EhFrameSection<ELFT>>(); - Add(In<ELFT>::EhFrame); + InX::EhFrame = make<EhFrameSection>(); + Add(InX::EhFrame); } if (InX::SymTab) @@ -417,8 +392,97 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() { Add(InX::StrTab); } +// The main function of the writer. +template <class ELFT> void Writer<ELFT>::run() { + // Create linker-synthesized sections such as .got or .plt. + // Such sections are of type input section. + createSyntheticSections<ELFT>(); + + if (!Config->Relocatable) + combineEhFrameSections<ELFT>(); + + // We want to process linker script commands. When SECTIONS command + // is given we let it create sections. + Script->processSectionCommands(); + + // Linker scripts controls how input sections are assigned to output sections. + // Input sections that were not handled by scripts are called "orphans", and + // they are assigned to output sections by the default rule. Process that. + Script->addOrphanSections(); + + if (Config->Discard != DiscardPolicy::All) + copyLocalSymbols(); + + if (Config->CopyRelocs) + addSectionSymbols(); + + // Now that we have a complete set of output sections. This function + // completes section contents. For example, we need to add strings + // to the string table, and add entries to .got and .plt. + // finalizeSections does that. + finalizeSections(); + if (errorCount()) + return; + + // If -compressed-debug-sections is specified, we need to compress + // .debug_* sections. Do it right now because it changes the size of + // output sections. + parallelForEach(OutputSections, + [](OutputSection *Sec) { Sec->maybeCompress<ELFT>(); }); + + Script->assignAddresses(); + Script->allocateHeaders(Phdrs); + + // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a + // 0 sized region. This has to be done late since only after assignAddresses + // we know the size of the sections. + removeEmptyPTLoad(); + + if (!Config->OFormatBinary) + assignFileOffsets(); + else + assignFileOffsetsBinary(); + + setPhdrs(); + + if (Config->Relocatable) { + for (OutputSection *Sec : OutputSections) + Sec->Addr = 0; + } + + // It does not make sense try to open the file if we have error already. + if (errorCount()) + return; + // Write the result down to a file. + openFile(); + if (errorCount()) + return; + + if (!Config->OFormatBinary) { + writeTrapInstr(); + writeHeader(); + writeSections(); + } else { + writeSectionsBinary(); + } + + // Backfill .note.gnu.build-id section content. This is done at last + // because the content is usually a hash value of the entire output file. + writeBuildId(); + if (errorCount()) + return; + + // Handle -Map option. + writeMapFile(); + if (errorCount()) + return; + + if (auto E = Buffer->commit()) + error("failed to write to the output file: " + toString(std::move(E))); +} + static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName, - const SymbolBody &B) { + const Symbol &B) { if (B.isFile() || B.isSection()) return false; @@ -443,27 +507,25 @@ static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName, return !Sec || !(Sec->Flags & SHF_MERGE); } -static bool includeInSymtab(const SymbolBody &B) { - if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj) +static bool includeInSymtab(const Symbol &B) { + if (!B.isLocal() && !B.IsUsedInRegularObj) return false; - if (auto *D = dyn_cast<DefinedRegular>(&B)) { + if (auto *D = dyn_cast<Defined>(&B)) { // Always include absolute symbols. SectionBase *Sec = D->Section; if (!Sec) return true; - if (auto *IS = dyn_cast<InputSectionBase>(Sec)) { - Sec = IS->Repl; - IS = cast<InputSectionBase>(Sec); - // Exclude symbols pointing to garbage-collected sections. - if (!IS->Live) - return false; - } + Sec = Sec->Repl; + // Exclude symbols pointing to garbage-collected sections. + if (isa<InputSectionBase>(Sec) && !Sec->Live) + return false; if (auto *S = dyn_cast<MergeInputSection>(Sec)) if (!S->getSectionPiece(D->Value)->Live) return false; + return true; } - return true; + return B.Used; } // Local symbols are not in the linker's symbol table. This function scans @@ -471,12 +533,13 @@ static bool includeInSymtab(const SymbolBody &B) { template <class ELFT> void Writer<ELFT>::copyLocalSymbols() { if (!InX::SymTab) return; - for (elf::ObjectFile<ELFT> *F : Symtab<ELFT>::X->getObjectFiles()) { - for (SymbolBody *B : F->getLocalSymbols()) { - if (!B->IsLocal) + for (InputFile *File : ObjectFiles) { + ObjFile<ELFT> *F = cast<ObjFile<ELFT>>(File); + for (Symbol *B : F->getLocalSymbols()) { + if (!B->isLocal()) fatal(toString(F) + ": broken object: getLocalSymbols returns a non-local symbol"); - auto *DR = dyn_cast<DefinedRegular>(B); + auto *DR = dyn_cast<Defined>(B); // No reason to keep local undefined symbol in symtab. if (!DR) @@ -493,27 +556,36 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() { } template <class ELFT> void Writer<ELFT>::addSectionSymbols() { - // Create one STT_SECTION symbol for each output section we might - // have a relocation with. - for (BaseCommand *Base : Script->Opt.Commands) { - auto *Cmd = dyn_cast<OutputSectionCommand>(Base); - if (!Cmd) + // Create a section symbol for each output section so that we can represent + // relocations that point to the section. If we know that no relocation is + // referring to a section (that happens if the section is a synthetic one), we + // don't create a section symbol for that section. + for (BaseCommand *Base : Script->SectionCommands) { + auto *Sec = dyn_cast<OutputSection>(Base); + if (!Sec) continue; - auto I = llvm::find_if(Cmd->Commands, [](BaseCommand *Base) { + auto I = llvm::find_if(Sec->SectionCommands, [](BaseCommand *Base) { if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) return !ISD->Sections.empty(); return false; }); - if (I == Cmd->Commands.end()) + if (I == Sec->SectionCommands.end()) continue; InputSection *IS = cast<InputSectionDescription>(*I)->Sections[0]; - if (isa<SyntheticSection>(IS) || IS->Type == SHT_REL || - IS->Type == SHT_RELA) + + // Relocations are not using REL[A] section symbols. + if (IS->Type == SHT_REL || IS->Type == SHT_RELA) + continue; + + // Unlike other synthetic sections, mergeable output sections contain data + // copied from input sections, and there may be a relocation pointing to its + // contents if -r or -emit-reloc are given. + if (isa<SyntheticSection>(IS) && !(IS->Flags & SHF_MERGE)) continue; auto *Sym = - make<DefinedRegular>("", /*IsLocal=*/true, /*StOther=*/0, STT_SECTION, - /*Value=*/0, /*Size=*/0, IS, nullptr); + make<Defined>(IS->File, "", STB_LOCAL, /*StOther=*/0, STT_SECTION, + /*Value=*/0, /*Size=*/0, IS); InX::SymTab->addSymbol(Sym); } } @@ -524,7 +596,7 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() { // // This function returns true if a section needs to be put into a // PT_GNU_RELRO segment. -bool elf::isRelroSection(const OutputSection *Sec) { +static bool isRelroSection(const OutputSection *Sec) { if (!Config->ZRelro) return false; @@ -575,20 +647,14 @@ bool elf::isRelroSection(const OutputSection *Sec) { if (Sec == InX::Dynamic->getParent()) return true; - // .bss.rel.ro is used for copy relocations for read-only symbols. - // Since the dynamic linker needs to process copy relocations, the - // section cannot be read-only, but once initialized, they shouldn't - // change. - if (Sec == InX::BssRelRo->getParent()) - return true; - // Sections with some special names are put into RELRO. This is a // bit unfortunate because section names shouldn't be significant in // ELF in spirit. But in reality many linker features depend on // magic section names. StringRef S = Sec->Name; - return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" || - S == ".eh_frame" || S == ".openbsd.randomdata"; + return S == ".data.rel.ro" || S == ".bss.rel.ro" || S == ".ctors" || + S == ".dtors" || S == ".jcr" || S == ".eh_frame" || + S == ".openbsd.randomdata"; } // We compute a rank for each section. The rank indicates where the @@ -696,8 +762,8 @@ static unsigned getSectionRank(const OutputSection *Sec) { if (IsNoBits) Rank |= RF_BSS; - // // Some architectures have additional ordering restrictions for sections - // // within the same PT_LOAD. + // Some architectures have additional ordering restrictions for sections + // within the same PT_LOAD. if (Config->EMachine == EM_PPC64) { // PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections // that we would like to make sure appear is a specific order to maximize @@ -735,8 +801,8 @@ static unsigned getSectionRank(const OutputSection *Sec) { } static bool compareSections(const BaseCommand *ACmd, const BaseCommand *BCmd) { - const OutputSection *A = cast<OutputSectionCommand>(ACmd)->Sec; - const OutputSection *B = cast<OutputSectionCommand>(BCmd)->Sec; + const OutputSection *A = cast<OutputSection>(ACmd); + const OutputSection *B = cast<OutputSection>(BCmd); if (A->SortRank != B->SortRank) return A->SortRank < B->SortRank; if (!(A->SortRank & RF_NOT_ADDR_SET)) @@ -746,36 +812,12 @@ static bool compareSections(const BaseCommand *ACmd, const BaseCommand *BCmd) { } void PhdrEntry::add(OutputSection *Sec) { - Last = Sec; - if (!First) - First = Sec; + LastSec = Sec; + if (!FirstSec) + FirstSec = Sec; p_align = std::max(p_align, Sec->Alignment); if (p_type == PT_LOAD) - Sec->FirstInPtLoad = First; -} - -template <class ELFT> -static Symbol *addRegular(StringRef Name, SectionBase *Sec, uint64_t Value, - uint8_t StOther = STV_HIDDEN, - uint8_t Binding = STB_WEAK) { - // The linker generated symbols are added as STB_WEAK to allow user defined - // ones to override them. - return Symtab<ELFT>::X->addRegular(Name, StOther, STT_NOTYPE, Value, - /*Size=*/0, Binding, Sec, - /*File=*/nullptr); -} - -template <class ELFT> -static DefinedRegular * -addOptionalRegular(StringRef Name, SectionBase *Sec, uint64_t Val, - uint8_t StOther = STV_HIDDEN, uint8_t Binding = STB_GLOBAL) { - SymbolBody *S = Symtab<ELFT>::X->find(Name); - if (!S) - return nullptr; - if (S->isInCurrentDSO()) - return nullptr; - return cast<DefinedRegular>( - addRegular<ELFT>(Name, Sec, Val, StOther, Binding)->body()); + Sec->PtLoad = this; } // The beginning and the ending of .rel[a].plt section are marked @@ -785,177 +827,115 @@ addOptionalRegular(StringRef Name, SectionBase *Sec, uint64_t Val, // need these symbols, since IRELATIVE relocs are resolved through GOT // and PLT. For details, see http://www.airs.com/blog/archives/403. template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() { - if (InX::DynSymTab) + if (!Config->Static) return; StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start"; - addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, 0, STV_HIDDEN, STB_WEAK); + addOptionalRegular<ELFT>(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK); S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end"; - addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, -1, STV_HIDDEN, STB_WEAK); + addOptionalRegular<ELFT>(S, InX::RelaIplt, -1, STV_HIDDEN, STB_WEAK); } -// The linker is expected to define some symbols depending on -// the linking result. This function defines such symbols. -template <class ELFT> void Writer<ELFT>::addReservedSymbols() { - if (Config->EMachine == EM_MIPS) { - // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer - // so that it points to an absolute address which by default is relative - // to GOT. Default offset is 0x7ff0. - // See "Global Data Symbols" in Chapter 6 in the following document: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - ElfSym::MipsGp = Symtab<ELFT>::X->addAbsolute("_gp", STV_HIDDEN, STB_LOCAL); - - // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between - // start of function and 'gp' pointer into GOT. - if (Symtab<ELFT>::X->find("_gp_disp")) - ElfSym::MipsGpDisp = - Symtab<ELFT>::X->addAbsolute("_gp_disp", STV_HIDDEN, STB_LOCAL); +template <class ELFT> +void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) { + // Scan all relocations. Each relocation goes through a series + // of tests to determine if it needs special treatment, such as + // creating GOT, PLT, copy relocations, etc. + // Note that relocations for non-alloc sections are directly + // processed by InputSection::relocateNonAlloc. + for (InputSectionBase *IS : InputSections) + if (IS->Live && isa<InputSection>(IS) && (IS->Flags & SHF_ALLOC)) + Fn(*IS); + for (EhInputSection *ES : InX::EhFrame->Sections) + Fn(*ES); +} - // The __gnu_local_gp is a magic symbol equal to the current value of 'gp' - // pointer. This symbol is used in the code generated by .cpload pseudo-op - // in case of using -mno-shared option. - // https://sourceware.org/ml/binutils/2004-12/msg00094.html - if (Symtab<ELFT>::X->find("__gnu_local_gp")) - ElfSym::MipsLocalGp = - Symtab<ELFT>::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL); +// This function generates assignments for predefined symbols (e.g. _end or +// _etext) and inserts them into the commands sequence to be processed at the +// appropriate time. This ensures that the value is going to be correct by the +// time any references to these symbols are processed and is equivalent to +// defining these symbols explicitly in the linker script. +template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() { + if (ElfSym::GlobalOffsetTable) { + // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to + // be at some offset from the base of the .got section, usually 0 or the end + // of the .got + InputSection *GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot) + : cast<InputSection>(InX::Got); + ElfSym::GlobalOffsetTable->Section = GotSection; } - // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to - // be at some offset from the base of the .got section, usually 0 or the end - // of the .got - InputSection *GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot) - : cast<InputSection>(InX::Got); - ElfSym::GlobalOffsetTable = addOptionalRegular<ELFT>( - "_GLOBAL_OFFSET_TABLE_", GotSection, Target->GotBaseSymOff); - - // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For - // static linking the linker is required to optimize away any references to - // __tls_get_addr, so it's not defined anywhere. Create a hidden definition - // to avoid the undefined symbol error. - if (!InX::DynSymTab) - Symtab<ELFT>::X->addIgnored("__tls_get_addr"); - - // __ehdr_start is the location of ELF file headers. Note that we define - // this symbol unconditionally even when using a linker script, which - // differs from the behavior implemented by GNU linker which only define - // this symbol if ELF headers are in the memory mapped segment. - // __executable_start is not documented, but the expectation of at - // least the android libc is that it points to the elf header too. - // __dso_handle symbol is passed to cxa_finalize as a marker to identify - // each DSO. The address of the symbol doesn't matter as long as they are - // different in different DSOs, so we chose the start address of the DSO. - for (const char *Name : - {"__ehdr_start", "__executable_start", "__dso_handle"}) - addOptionalRegular<ELFT>(Name, Out::ElfHeader, 0, STV_HIDDEN); - - // If linker script do layout we do not need to create any standart symbols. - if (Script->Opt.HasSections) - return; - - auto Add = [](StringRef S) { - return addOptionalRegular<ELFT>(S, Out::ElfHeader, 0, STV_DEFAULT); - }; - - ElfSym::Bss = Add("__bss_start"); - ElfSym::End1 = Add("end"); - ElfSym::End2 = Add("_end"); - ElfSym::Etext1 = Add("etext"); - ElfSym::Etext2 = Add("_etext"); - ElfSym::Edata1 = Add("edata"); - ElfSym::Edata2 = Add("_edata"); -} - -// Sort input sections by section name suffixes for -// __attribute__((init_priority(N))). -static void sortInitFini(OutputSectionCommand *Cmd) { - if (Cmd) - Cmd->sortInitFini(); -} + PhdrEntry *Last = nullptr; + PhdrEntry *LastRO = nullptr; -// Sort input sections by the special rule for .ctors and .dtors. -static void sortCtorsDtors(OutputSectionCommand *Cmd) { - if (Cmd) - Cmd->sortCtorsDtors(); -} + for (PhdrEntry *P : Phdrs) { + if (P->p_type != PT_LOAD) + continue; + Last = P; + if (!(P->p_flags & PF_W)) + LastRO = P; + } -// Sort input sections using the list provided by --symbol-ordering-file. -template <class ELFT> static void sortBySymbolsOrder() { - if (Config->SymbolOrderingFile.empty()) - return; + if (LastRO) { + // _etext is the first location after the last read-only loadable segment. + if (ElfSym::Etext1) + ElfSym::Etext1->Section = LastRO->LastSec; + if (ElfSym::Etext2) + ElfSym::Etext2->Section = LastRO->LastSec; + } - // Build a map from symbols to their priorities. Symbols that didn't - // appear in the symbol ordering file have the lowest priority 0. - // All explicitly mentioned symbols have negative (higher) priorities. - DenseMap<StringRef, int> SymbolOrder; - int Priority = -Config->SymbolOrderingFile.size(); - for (StringRef S : Config->SymbolOrderingFile) - SymbolOrder.insert({S, Priority++}); - - // Build a map from sections to their priorities. - DenseMap<SectionBase *, int> SectionOrder; - for (elf::ObjectFile<ELFT> *File : Symtab<ELFT>::X->getObjectFiles()) { - for (SymbolBody *Body : File->getSymbols()) { - auto *D = dyn_cast<DefinedRegular>(Body); - if (!D || !D->Section) - continue; - int &Priority = SectionOrder[D->Section]; - Priority = std::min(Priority, SymbolOrder.lookup(D->getName())); + if (Last) { + // _edata points to the end of the last mapped initialized section. + OutputSection *Edata = nullptr; + for (OutputSection *OS : OutputSections) { + if (OS->Type != SHT_NOBITS) + Edata = OS; + if (OS == Last->LastSec) + break; } - } - // Sort sections by priority. - for (BaseCommand *Base : Script->Opt.Commands) - if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) - Cmd->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); }); -} + if (ElfSym::Edata1) + ElfSym::Edata1->Section = Edata; + if (ElfSym::Edata2) + ElfSym::Edata2->Section = Edata; -template <class ELFT> -void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) { - for (InputSectionBase *IS : InputSections) { - if (!IS->Live) - continue; - // Scan all relocations. Each relocation goes through a series - // of tests to determine if it needs special treatment, such as - // creating GOT, PLT, copy relocations, etc. - // Note that relocations for non-alloc sections are directly - // processed by InputSection::relocateNonAlloc. - if (!(IS->Flags & SHF_ALLOC)) - continue; - if (isa<InputSection>(IS) || isa<EhInputSection>(IS)) - Fn(*IS); + // _end is the first location after the uninitialized data region. + if (ElfSym::End1) + ElfSym::End1->Section = Last->LastSec; + if (ElfSym::End2) + ElfSym::End2->Section = Last->LastSec; } - if (!Config->Relocatable) { - for (EhInputSection *ES : In<ELFT>::EhFrame->Sections) - Fn(*ES); - } -} + if (ElfSym::Bss) + ElfSym::Bss->Section = findSection(".bss"); -template <class ELFT> void Writer<ELFT>::createSections() { - for (InputSectionBase *IS : InputSections) - if (IS) - Factory.addInputSec(IS, getOutputSectionName(IS->Name)); - - Script->fabricateDefaultCommands(); - sortBySymbolsOrder<ELFT>(); - sortInitFini(findSectionCommand(".init_array")); - sortInitFini(findSectionCommand(".fini_array")); - sortCtorsDtors(findSectionCommand(".ctors")); - sortCtorsDtors(findSectionCommand(".dtors")); + // Setup MIPS _gp_disp/__gnu_local_gp symbols which should + // be equal to the _gp symbol's value. + if (ElfSym::MipsGp) { + // Find GP-relative section with the lowest address + // and use this address to calculate default _gp value. + for (OutputSection *OS : OutputSections) { + if (OS->Flags & SHF_MIPS_GPREL) { + ElfSym::MipsGp->Section = OS; + ElfSym::MipsGp->Value = 0x7ff0; + break; + } + } + } } // We want to find how similar two ranks are. // The more branches in getSectionRank that match, the more similar they are. // Since each branch corresponds to a bit flag, we can just use // countLeadingZeros. -static int getRankProximity(OutputSection *A, OutputSection *B) { +static int getRankProximityAux(OutputSection *A, OutputSection *B) { return countLeadingZeros(A->SortRank ^ B->SortRank); } static int getRankProximity(OutputSection *A, BaseCommand *B) { - if (auto *Cmd = dyn_cast<OutputSectionCommand>(B)) - if (Cmd->Sec) - return getRankProximity(A, Cmd->Sec); + if (auto *Sec = dyn_cast<OutputSection>(B)) + if (Sec->Live) + return getRankProximityAux(A, Sec); return -1; } @@ -974,7 +954,7 @@ static int getRankProximity(OutputSection *A, BaseCommand *B) { // rw_sec : { *(rw_sec) } // would mean that the RW PT_LOAD would become unaligned. static bool shouldSkip(BaseCommand *Cmd) { - if (isa<OutputSectionCommand>(Cmd)) + if (isa<OutputSection>(Cmd)) return false; if (auto *Assign = dyn_cast<SymbolAssignment>(Cmd)) return Assign->Name != "."; @@ -988,7 +968,7 @@ template <typename ELFT> static std::vector<BaseCommand *>::iterator findOrphanPos(std::vector<BaseCommand *>::iterator B, std::vector<BaseCommand *>::iterator E) { - OutputSection *Sec = cast<OutputSectionCommand>(*E)->Sec; + OutputSection *Sec = cast<OutputSection>(*E); // Find the first element that has as close a rank as possible. auto I = std::max_element(B, E, [=](BaseCommand *A, BaseCommand *B) { @@ -1000,44 +980,84 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B, // Consider all existing sections with the same proximity. int Proximity = getRankProximity(Sec, *I); for (; I != E; ++I) { - auto *Cmd = dyn_cast<OutputSectionCommand>(*I); - if (!Cmd || !Cmd->Sec) + auto *CurSec = dyn_cast<OutputSection>(*I); + if (!CurSec || !CurSec->Live) continue; - if (getRankProximity(Sec, Cmd->Sec) != Proximity || - Sec->SortRank < Cmd->Sec->SortRank) + if (getRankProximity(Sec, CurSec) != Proximity || + Sec->SortRank < CurSec->SortRank) break; } - auto J = std::find_if( - llvm::make_reverse_iterator(I), llvm::make_reverse_iterator(B), - [](BaseCommand *Cmd) { return isa<OutputSectionCommand>(Cmd); }); + + auto IsLiveSection = [](BaseCommand *Cmd) { + auto *OS = dyn_cast<OutputSection>(Cmd); + return OS && OS->Live; + }; + + auto J = std::find_if(llvm::make_reverse_iterator(I), + llvm::make_reverse_iterator(B), IsLiveSection); I = J.base(); + + // As a special case, if the orphan section is the last section, put + // it at the very end, past any other commands. + // This matches bfd's behavior and is convenient when the linker script fully + // specifies the start of the file, but doesn't care about the end (the non + // alloc sections for example). + auto NextSec = std::find_if(I, E, IsLiveSection); + if (NextSec == E) + return E; + while (I != E && shouldSkip(*I)) ++I; return I; } +// If no layout was provided by linker script, we want to apply default +// sorting for special input sections and handle --symbol-ordering-file. +template <class ELFT> void Writer<ELFT>::sortInputSections() { + assert(!Script->HasSectionsCommand); + + // Sort input sections by priority using the list provided + // by --symbol-ordering-file. + DenseMap<SectionBase *, int> Order = buildSectionOrder(); + if (!Order.empty()) + for (BaseCommand *Base : Script->SectionCommands) + if (auto *Sec = dyn_cast<OutputSection>(Base)) + if (Sec->Live) + Sec->sort([&](InputSectionBase *S) { return Order.lookup(S); }); + + // Sort input sections by section name suffixes for + // __attribute__((init_priority(N))). + if (OutputSection *Sec = findSection(".init_array")) + Sec->sortInitFini(); + if (OutputSection *Sec = findSection(".fini_array")) + Sec->sortInitFini(); + + // Sort input sections by the special rule for .ctors and .dtors. + if (OutputSection *Sec = findSection(".ctors")) + Sec->sortCtorsDtors(); + if (OutputSection *Sec = findSection(".dtors")) + Sec->sortCtorsDtors(); +} + template <class ELFT> void Writer<ELFT>::sortSections() { - if (Script->Opt.HasSections) - Script->adjustSectionsBeforeSorting(); + Script->adjustSectionsBeforeSorting(); // Don't sort if using -r. It is not necessary and we want to preserve the // relative order for SHF_LINK_ORDER sections. if (Config->Relocatable) return; - for (BaseCommand *Base : Script->Opt.Commands) - if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) - if (OutputSection *Sec = Cmd->Sec) - Sec->SortRank = getSectionRank(Sec); - - if (!Script->Opt.HasSections) { - // We know that all the OutputSectionCommands are contiguous in - // this case. - auto E = Script->Opt.Commands.end(); - auto I = Script->Opt.Commands.begin(); - auto IsSection = [](BaseCommand *Base) { - return isa<OutputSectionCommand>(Base); - }; + for (BaseCommand *Base : Script->SectionCommands) + if (auto *Sec = dyn_cast<OutputSection>(Base)) + Sec->SortRank = getSectionRank(Sec); + + if (!Script->HasSectionsCommand) { + sortInputSections(); + + // We know that all the OutputSections are contiguous in this case. + auto E = Script->SectionCommands.end(); + auto I = Script->SectionCommands.begin(); + auto IsSection = [](BaseCommand *Base) { return isa<OutputSection>(Base); }; I = std::find_if(I, E, IsSection); E = std::find_if(llvm::make_reverse_iterator(E), llvm::make_reverse_iterator(I), IsSection) @@ -1077,7 +1097,7 @@ template <class ELFT> void Writer<ELFT>::sortSections() { // a PT_LOAD. // // There is some ambiguity as to where exactly a new entry should be - // inserted, because Opt.Commands contains not only output section + // inserted, because Commands contains not only output section // commands but also other types of commands such as symbol assignment // expressions. There's no correct answer here due to the lack of the // formal specification of the linker script. We use heuristics to @@ -1085,11 +1105,11 @@ template <class ELFT> void Writer<ELFT>::sortSections() { // after another commands. For the details, look at shouldSkip // function. - auto I = Script->Opt.Commands.begin(); - auto E = Script->Opt.Commands.end(); + auto I = Script->SectionCommands.begin(); + auto E = Script->SectionCommands.end(); auto NonScriptI = std::find_if(I, E, [](BaseCommand *Base) { - if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) - return Cmd->Sec && Cmd->Sec->SectionIndex == INT_MAX; + if (auto *Sec = dyn_cast<OutputSection>(Base)) + return Sec->Live && Sec->SectionIndex == INT_MAX; return false; }); @@ -1109,13 +1129,13 @@ template <class ELFT> void Writer<ELFT>::sortSections() { while (NonScriptI != E) { auto Pos = findOrphanPos<ELFT>(I, NonScriptI); - OutputSection *Orphan = cast<OutputSectionCommand>(*NonScriptI)->Sec; + OutputSection *Orphan = cast<OutputSection>(*NonScriptI); // As an optimization, find all sections with the same sort rank // and insert them with one rotate. unsigned Rank = Orphan->SortRank; auto End = std::find_if(NonScriptI + 1, E, [=](BaseCommand *Cmd) { - return cast<OutputSectionCommand>(Cmd)->Sec->SortRank != Rank; + return cast<OutputSection>(Cmd)->SortRank != Rank; }); std::rotate(Pos, NonScriptI, End); NonScriptI = End; @@ -1124,6 +1144,125 @@ template <class ELFT> void Writer<ELFT>::sortSections() { Script->adjustSectionsAfterSorting(); } +static bool compareByFilePosition(InputSection *A, InputSection *B) { + // Synthetic doesn't have link order dependecy, stable_sort will keep it last + if (A->kind() == InputSectionBase::Synthetic || + B->kind() == InputSectionBase::Synthetic) + return false; + InputSection *LA = A->getLinkOrderDep(); + InputSection *LB = B->getLinkOrderDep(); + OutputSection *AOut = LA->getParent(); + OutputSection *BOut = LB->getParent(); + if (AOut != BOut) + return AOut->SectionIndex < BOut->SectionIndex; + return LA->OutSecOff < LB->OutSecOff; +} + +// This function is used by the --merge-exidx-entries to detect duplicate +// .ARM.exidx sections. It is Arm only. +// +// The .ARM.exidx section is of the form: +// | PREL31 offset to function | Unwind instructions for function | +// where the unwind instructions are either a small number of unwind +// instructions inlined into the table entry, the special CANT_UNWIND value of +// 0x1 or a PREL31 offset into a .ARM.extab Section that contains unwind +// instructions. +// +// We return true if all the unwind instructions in the .ARM.exidx entries of +// Cur can be merged into the last entry of Prev. +static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) { + + // References to .ARM.Extab Sections have bit 31 clear and are not the + // special EXIDX_CANTUNWIND bit-pattern. + auto IsExtabRef = [](uint32_t Unwind) { + return (Unwind & 0x80000000) == 0 && Unwind != 0x1; + }; + + struct ExidxEntry { + ulittle32_t Fn; + ulittle32_t Unwind; + }; + + // Get the last table Entry from the previous .ARM.exidx section. + const ExidxEntry &PrevEntry = *reinterpret_cast<const ExidxEntry *>( + Prev->Data.data() + Prev->getSize() - sizeof(ExidxEntry)); + if (IsExtabRef(PrevEntry.Unwind)) + return false; + + // We consider the unwind instructions of an .ARM.exidx table entry + // a duplicate if the previous unwind instructions if: + // - Both are the special EXIDX_CANTUNWIND. + // - Both are the same inline unwind instructions. + // We do not attempt to follow and check links into .ARM.extab tables as + // consecutive identical entries are rare and the effort to check that they + // are identical is high. + + if (isa<SyntheticSection>(Cur)) + // Exidx sentinel section has implicit EXIDX_CANTUNWIND; + return PrevEntry.Unwind == 0x1; + + ArrayRef<const ExidxEntry> Entries( + reinterpret_cast<const ExidxEntry *>(Cur->Data.data()), + Cur->getSize() / sizeof(ExidxEntry)); + for (const ExidxEntry &Entry : Entries) + if (IsExtabRef(Entry.Unwind) || Entry.Unwind != PrevEntry.Unwind) + return false; + // All table entries in this .ARM.exidx Section can be merged into the + // previous Section. + return true; +} + +template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() { + for (OutputSection *Sec : OutputSections) { + if (!(Sec->Flags & SHF_LINK_ORDER)) + continue; + + // Link order may be distributed across several InputSectionDescriptions + // but sort must consider them all at once. + std::vector<InputSection **> ScriptSections; + std::vector<InputSection *> Sections; + for (BaseCommand *Base : Sec->SectionCommands) { + if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) { + for (InputSection *&IS : ISD->Sections) { + ScriptSections.push_back(&IS); + Sections.push_back(IS); + } + } + } + std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition); + + if (Config->MergeArmExidx && !Config->Relocatable && + Config->EMachine == EM_ARM && Sec->Type == SHT_ARM_EXIDX) { + // The EHABI for the Arm Architecture permits consecutive identical + // table entries to be merged. We use a simple implementation that + // removes a .ARM.exidx Input Section if it can be merged into the + // previous one. This does not require any rewriting of InputSection + // contents but misses opportunities for fine grained deduplication where + // only a subset of the InputSection contents can be merged. + int Cur = 1; + int Prev = 0; + int N = Sections.size(); + while (Cur < N) { + if (isDuplicateArmExidxSec(Sections[Prev], Sections[Cur])) + Sections[Cur] = nullptr; + else + Prev = Cur; + ++Cur; + } + } + + for (int I = 0, N = Sections.size(); I < N; ++I) + *ScriptSections[I] = Sections[I]; + + // Remove the Sections we marked as duplicate earlier. + for (BaseCommand *Base : Sec->SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) + ISD->Sections.erase( + std::remove(ISD->Sections.begin(), ISD->Sections.end(), nullptr), + ISD->Sections.end()); + } +} + static void applySynthetic(const std::vector<SyntheticSection *> &Sections, std::function<void(SyntheticSection *)> Fn) { for (SyntheticSection *SS : Sections) @@ -1131,10 +1270,18 @@ static void applySynthetic(const std::vector<SyntheticSection *> &Sections, Fn(SS); } -// We need to add input synthetic sections early in createSyntheticSections() -// to make them visible from linkescript side. But not all sections are always -// required to be in output. For example we don't need dynamic section content -// sometimes. This function filters out such unused sections from the output. +// In order to allow users to manipulate linker-synthesized sections, +// we had to add synthetic sections to the input section list early, +// even before we make decisions whether they are needed. This allows +// users to write scripts like this: ".mygot : { .got }". +// +// Doing it has an unintended side effects. If it turns out that we +// don't need a .got (for example) at all because there's no +// relocation that needs a .got, we don't want to emit .got. +// +// To deal with the above problem, this function is called after +// scanRelocations is called to remove synthetic sections that turn +// out to be empty. static void removeUnusedSyntheticSections() { // All input synthetic sections that can be empty are placed after // all regular ones. We iterate over them all and exit at first @@ -1146,55 +1293,73 @@ static void removeUnusedSyntheticSections() { OutputSection *OS = SS->getParent(); if (!SS->empty() || !OS) continue; - if ((SS == InX::Got || SS == InX::MipsGot) && ElfSym::GlobalOffsetTable) - continue; - OutputSectionCommand *Cmd = Script->getCmd(OS); - std::vector<BaseCommand *>::iterator Empty = Cmd->Commands.end(); - for (auto I = Cmd->Commands.begin(), E = Cmd->Commands.end(); I != E; ++I) { + std::vector<BaseCommand *>::iterator Empty = OS->SectionCommands.end(); + for (auto I = OS->SectionCommands.begin(), E = OS->SectionCommands.end(); + I != E; ++I) { BaseCommand *B = *I; if (auto *ISD = dyn_cast<InputSectionDescription>(B)) { - auto P = std::find(ISD->Sections.begin(), ISD->Sections.end(), SS); - if (P != ISD->Sections.end()) - ISD->Sections.erase(P); + llvm::erase_if(ISD->Sections, + [=](InputSection *IS) { return IS == SS; }); if (ISD->Sections.empty()) Empty = I; } } - if (Empty != Cmd->Commands.end()) - Cmd->Commands.erase(Empty); + if (Empty != OS->SectionCommands.end()) + OS->SectionCommands.erase(Empty); // If there are no other sections in the output section, remove it from the // output. - if (Cmd->Commands.empty()) { - // Also remove script commands matching the output section. - auto &Cmds = Script->Opt.Commands; - auto I = std::remove_if(Cmds.begin(), Cmds.end(), [&](BaseCommand *Cmd) { - if (auto *OSCmd = dyn_cast<OutputSectionCommand>(Cmd)) - return OSCmd->Sec == OS; - return false; - }); - Cmds.erase(I, Cmds.end()); - } + if (OS->SectionCommands.empty()) + OS->Live = false; } } +// Returns true if a symbol can be replaced at load-time by a symbol +// with the same name defined in other ELF executable or DSO. +static bool computeIsPreemptible(const Symbol &B) { + assert(!B.isLocal()); + // Only symbols that appear in dynsym can be preempted. + if (!B.includeInDynsym()) + return false; + + // Only default visibility symbols can be preempted. + if (B.Visibility != STV_DEFAULT) + return false; + + // At this point copy relocations have not been created yet, so any + // symbol that is not defined locally is preemptible. + if (!B.isDefined()) + return true; + + // If we have a dynamic list it specifies which local symbols are preemptible. + if (Config->HasDynamicList) + return false; + + if (!Config->Shared) + return false; + + // -Bsymbolic means that definitions are not preempted. + if (Config->Bsymbolic || (Config->BsymbolicFunctions && B.isFunc())) + return false; + return true; +} + // Create output section objects and add them to OutputSections. template <class ELFT> void Writer<ELFT>::finalizeSections() { - Out::DebugInfo = findSectionInScript(".debug_info"); - Out::PreinitArray = findSectionInScript(".preinit_array"); - Out::InitArray = findSectionInScript(".init_array"); - Out::FiniArray = findSectionInScript(".fini_array"); + Out::DebugInfo = findSection(".debug_info"); + Out::PreinitArray = findSection(".preinit_array"); + Out::InitArray = findSection(".init_array"); + Out::FiniArray = findSection(".fini_array"); // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop // symbols for sections, so that the runtime can get the start and end // addresses of each section by section name. Add such symbols. if (!Config->Relocatable) { addStartEndSymbols(); - for (BaseCommand *Base : Script->Opt.Commands) - if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) - if (Cmd->Sec) - addStartStopSymbols(Cmd->Sec); + for (BaseCommand *Base : Script->SectionCommands) + if (auto *Sec = dyn_cast<OutputSection>(Base)) + addStartStopSymbols(Sec); } // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type. @@ -1202,7 +1367,9 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // Even the author of gold doesn't remember why gold behaves that way. // https://sourceware.org/ml/binutils/2002-03/msg00360.html if (InX::DynSymTab) - addRegular<ELFT>("_DYNAMIC", InX::Dynamic, 0); + Symtab->addRegular<ELFT>("_DYNAMIC", STV_HIDDEN, STT_NOTYPE, 0 /*Value*/, + /*Size=*/0, STB_WEAK, InX::Dynamic, + /*File=*/nullptr); // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols(); @@ -1210,12 +1377,16 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // This responsible for splitting up .eh_frame section into // pieces. The relocation scan uses those pieces, so this has to be // earlier. - applySynthetic({In<ELFT>::EhFrame}, + applySynthetic({InX::EhFrame}, [](SyntheticSection *SS) { SS->finalizeContents(); }); + for (Symbol *S : Symtab->getSymbols()) + S->IsPreemptible |= computeIsPreemptible(*S); + // Scan relocations. This must be done after every symbol is declared so that // we can correctly decide if a dynamic relocation is needed. - forEachRelSec(scanRelocations<ELFT>); + if (!Config->Relocatable) + forEachRelSec(scanRelocations<ELFT>); if (InX::Plt && !InX::Plt->empty()) InX::Plt->addSymbols(); @@ -1224,42 +1395,41 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // Now that we have defined all possible global symbols including linker- // synthesized ones. Visit all symbols to give the finishing touches. - for (Symbol *S : Symtab<ELFT>::X->getSymbols()) { - SymbolBody *Body = S->body(); - - if (!includeInSymtab(*Body)) + for (Symbol *Sym : Symtab->getSymbols()) { + if (!includeInSymtab(*Sym)) continue; if (InX::SymTab) - InX::SymTab->addSymbol(Body); + InX::SymTab->addSymbol(Sym); - if (InX::DynSymTab && S->includeInDynsym()) { - InX::DynSymTab->addSymbol(Body); - if (auto *SS = dyn_cast<SharedSymbol>(Body)) - if (cast<SharedFile<ELFT>>(SS->File)->isNeeded()) + if (InX::DynSymTab && Sym->includeInDynsym()) { + InX::DynSymTab->addSymbol(Sym); + if (auto *SS = dyn_cast<SharedSymbol>(Sym)) + if (cast<SharedFile<ELFT>>(Sym->File)->IsNeeded) In<ELFT>::VerNeed->addSymbol(SS); } } // Do not proceed if there was an undefined symbol. - if (ErrorCount) + if (errorCount()) return; addPredefinedSections(); removeUnusedSyntheticSections(); sortSections(); + Script->removeEmptyCommands(); // Now that we have the final list, create a list of all the - // OutputSectionCommands for convenience. - for (BaseCommand *Base : Script->Opt.Commands) - if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) - OutputSectionCommands.push_back(Cmd); + // OutputSections for convenience. + for (BaseCommand *Base : Script->SectionCommands) + if (auto *Sec = dyn_cast<OutputSection>(Base)) + OutputSections.push_back(Sec); // Prefer command line supplied address over other constraints. - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - auto I = Config->SectionStartMap.find(Cmd->Name); + for (OutputSection *Sec : OutputSections) { + auto I = Config->SectionStartMap.find(Sec->Name); if (I != Config->SectionStartMap.end()) - Cmd->AddrExpr = [=] { return I->second; }; + Sec->AddrExpr = [=] { return I->second; }; } // This is a bit of a hack. A value of 0 means undef, so we set it @@ -1268,8 +1438,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { Out::ElfHeader->SectionIndex = 1; unsigned I = 1; - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; + for (OutputSection *Sec : OutputSections) { Sec->SectionIndex = I++; Sec->ShName = InX::ShStrTab->addString(Sec->Name); } @@ -1283,64 +1452,73 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size(); } + // Some symbols are defined in term of program headers. Now that we + // have the headers, we can find out which sections they point to. + setReservedSymbolSections(); + // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. - applySynthetic({InX::DynSymTab, InX::Bss, InX::BssRelRo, - InX::GnuHashTab, In<ELFT>::HashTab, InX::SymTab, - InX::ShStrTab, InX::StrTab, In<ELFT>::VerDef, - InX::DynStrTab, InX::GdbIndex, InX::Got, - InX::MipsGot, InX::IgotPlt, InX::GotPlt, - In<ELFT>::RelaDyn, In<ELFT>::RelaIplt, In<ELFT>::RelaPlt, - InX::Plt, InX::Iplt, In<ELFT>::EhFrameHdr, - In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic}, - [](SyntheticSection *SS) { SS->finalizeContents(); }); + applySynthetic( + {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab, + InX::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab, + In<ELFT>::VerDef, InX::DynStrTab, InX::Got, InX::MipsGot, + InX::IgotPlt, InX::GotPlt, InX::RelaDyn, InX::RelaIplt, + InX::RelaPlt, InX::Plt, InX::Iplt, InX::EhFrameHdr, + In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic}, + [](SyntheticSection *SS) { SS->finalizeContents(); }); + + if (!Script->HasSectionsCommand && !Config->Relocatable) + fixSectionAlignments(); + + // After link order processing .ARM.exidx sections can be deduplicated, which + // needs to be resolved before any other address dependent operation. + resolveShfLinkOrder(); - // Some architectures use small displacements for jump instructions. - // It is linker's responsibility to create thunks containing long - // jump instructions if jump targets are too far. Create thunks. - if (Target->NeedsThunks) { - // FIXME: only ARM Interworking and Mips LA25 Thunks are implemented, - // these - // do not require address information. To support range extension Thunks - // we need to assign addresses so that we can tell if jump instructions - // are out of range. This will need to turn into a loop that converges - // when no more Thunks are added + // Some architectures need to generate content that depends on the address + // of InputSections. For example some architectures use small displacements + // for jump instructions that is is the linker's responsibility for creating + // range extension thunks for. As the generation of the content may also + // alter InputSection addresses we must converge to a fixed point. + if (Target->NeedsThunks || Config->AndroidPackDynRelocs) { ThunkCreator TC; - Script->assignAddresses(); - if (TC.createThunks(OutputSectionCommands)) { - applySynthetic({InX::MipsGot}, - [](SyntheticSection *SS) { SS->updateAllocSize(); }); - if (TC.createThunks(OutputSectionCommands)) - fatal("All non-range thunks should be created in first call"); - } + AArch64Err843419Patcher A64P; + bool Changed; + do { + Script->assignAddresses(); + Changed = false; + if (Target->NeedsThunks) + Changed |= TC.createThunks(OutputSections); + if (Config->FixCortexA53Errata843419) { + if (Changed) + Script->assignAddresses(); + Changed |= A64P.createFixes(); + } + if (InX::MipsGot) + InX::MipsGot->updateAllocSize(); + Changed |= InX::RelaDyn->updateAllocSize(); + } while (Changed); } // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result // of finalizing other sections. - for (OutputSectionCommand *Cmd : OutputSectionCommands) - Cmd->finalize<ELFT>(); + for (OutputSection *Sec : OutputSections) + Sec->finalize<ELFT>(); // createThunks may have added local symbols to the static symbol table - applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab}, + applySynthetic({InX::SymTab}, [](SyntheticSection *SS) { SS->postThunkContents(); }); } template <class ELFT> void Writer<ELFT>::addPredefinedSections() { // ARM ABI requires .ARM.exidx to be terminated by some piece of data. // We have the terminater synthetic section class. Add that at the end. - OutputSectionCommand *Cmd = findSectionCommand(".ARM.exidx"); - if (!Cmd || !Cmd->Sec || Config->Relocatable) + OutputSection *Cmd = findSection(".ARM.exidx"); + if (!Cmd || !Cmd->Live || Config->Relocatable) return; auto *Sentinel = make<ARMExidxSentinelSection>(); - Cmd->Sec->addSection(Sentinel); - // Add the sentinel to the last of these too. - auto ISD = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(), - [](const BaseCommand *Base) { - return isa<InputSectionDescription>(Base); - }); - cast<InputSectionDescription>(*ISD)->Sections.push_back(Sentinel); + Cmd->addSection(Sentinel); } // The linker is expected to define SECNAME_start and SECNAME_end @@ -1364,7 +1542,7 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() { Define("__init_array_start", "__init_array_end", Out::InitArray); Define("__fini_array_start", "__fini_array_end", Out::FiniArray); - if (OutputSection *Sec = findSectionInScript(".ARM.exidx")) + if (OutputSection *Sec = findSection(".ARM.exidx")) Define("__exidx_start", "__exidx_end", Sec); } @@ -1382,22 +1560,6 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) { addOptionalRegular<ELFT>(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); } -template <class ELFT> -OutputSectionCommand *Writer<ELFT>::findSectionCommand(StringRef Name) { - for (BaseCommand *Base : Script->Opt.Commands) - if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) - if (Cmd->Name == Name) - return Cmd; - return nullptr; -} - -template <class ELFT> -OutputSection *Writer<ELFT>::findSectionInScript(StringRef Name) { - if (OutputSectionCommand *Cmd = findSectionCommand(Name)) - return Cmd->Sec; - return nullptr; -} - static bool needsPtLoad(OutputSection *Sec) { if (!(Sec->Flags & SHF_ALLOC)) return false; @@ -1424,19 +1586,19 @@ static uint64_t computeFlags(uint64_t Flags) { // Decide which program headers to create and which sections to include in each // one. -template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() { - std::vector<PhdrEntry> Ret; +template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() { + std::vector<PhdrEntry *> Ret; auto AddHdr = [&](unsigned Type, unsigned Flags) -> PhdrEntry * { - Ret.emplace_back(Type, Flags); - return &Ret.back(); + Ret.push_back(make<PhdrEntry>(Type, Flags)); + return Ret.back(); }; // The first phdr entry is PT_PHDR which describes the program header itself. AddHdr(PT_PHDR, PF_R)->add(Out::ProgramHeaders); // PT_INTERP must be the second entry if exists. - if (OutputSection *Sec = findSectionInScript(".interp")) - AddHdr(PT_INTERP, Sec->getPhdrFlags())->add(Sec); + if (OutputSection *Cmd = findSection(".interp")) + AddHdr(PT_INTERP, Cmd->getPhdrFlags())->add(Cmd); // Add the first PT_LOAD segment for regular output sections. uint64_t Flags = computeFlags(PF_R); @@ -1446,8 +1608,7 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() { Load->add(Out::ElfHeader); Load->add(Out::ProgramHeaders); - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; + for (OutputSection *Sec : OutputSections) { if (!(Sec->Flags & SHF_ALLOC)) break; if (!needsPtLoad(Sec)) @@ -1459,7 +1620,7 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() { // different flags or is loaded at a discontiguous address using AT linker // script command. uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); - if (Cmd->LMAExpr || Flags != NewFlags) { + if (Sec->LMAExpr || Flags != NewFlags) { Load = AddHdr(PT_LOAD, NewFlags); Flags = NewFlags; } @@ -1468,14 +1629,12 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() { } // Add a TLS segment if any. - PhdrEntry TlsHdr(PT_TLS, PF_R); - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; + PhdrEntry *TlsHdr = make<PhdrEntry>(PT_TLS, PF_R); + for (OutputSection *Sec : OutputSections) if (Sec->Flags & SHF_TLS) - TlsHdr.add(Sec); - } - if (TlsHdr.First) - Ret.push_back(std::move(TlsHdr)); + TlsHdr->add(Sec); + if (TlsHdr->FirstSec) + Ret.push_back(TlsHdr); // Add an entry for .dynamic. if (InX::DynSymTab) @@ -1484,25 +1643,39 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() { // PT_GNU_RELRO includes all sections that should be marked as // read-only by dynamic linker after proccessing relocations. - PhdrEntry RelRo(PT_GNU_RELRO, PF_R); - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; - if (needsPtLoad(Sec) && isRelroSection(Sec)) - RelRo.add(Sec); + // Current dynamic loaders only support one PT_GNU_RELRO PHDR, give + // an error message if more than one PT_GNU_RELRO PHDR is required. + PhdrEntry *RelRo = make<PhdrEntry>(PT_GNU_RELRO, PF_R); + bool InRelroPhdr = false; + bool IsRelroFinished = false; + for (OutputSection *Sec : OutputSections) { + if (!needsPtLoad(Sec)) + continue; + if (isRelroSection(Sec)) { + InRelroPhdr = true; + if (!IsRelroFinished) + RelRo->add(Sec); + else + error("section: " + Sec->Name + " is not contiguous with other relro" + + " sections"); + } else if (InRelroPhdr) { + InRelroPhdr = false; + IsRelroFinished = true; + } } - if (RelRo.First) - Ret.push_back(std::move(RelRo)); + if (RelRo->FirstSec) + Ret.push_back(RelRo); // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr. - if (!In<ELFT>::EhFrame->empty() && In<ELFT>::EhFrameHdr && - In<ELFT>::EhFrame->getParent() && In<ELFT>::EhFrameHdr->getParent()) - AddHdr(PT_GNU_EH_FRAME, In<ELFT>::EhFrameHdr->getParent()->getPhdrFlags()) - ->add(In<ELFT>::EhFrameHdr->getParent()); + if (!InX::EhFrame->empty() && InX::EhFrameHdr && InX::EhFrame->getParent() && + InX::EhFrameHdr->getParent()) + AddHdr(PT_GNU_EH_FRAME, InX::EhFrameHdr->getParent()->getPhdrFlags()) + ->add(InX::EhFrameHdr->getParent()); // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes // the dynamic linker fill the segment with random data. - if (OutputSection *Sec = findSectionInScript(".openbsd.randomdata")) - AddHdr(PT_OPENBSD_RANDOMIZE, Sec->getPhdrFlags())->add(Sec); + if (OutputSection *Cmd = findSection(".openbsd.randomdata")) + AddHdr(PT_OPENBSD_RANDOMIZE, Cmd->getPhdrFlags())->add(Cmd); // PT_GNU_STACK is a special section to tell the loader to make the // pages for the stack non-executable. If you really want an executable @@ -1524,10 +1697,9 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() { // Create one PT_NOTE per a group of contiguous .note sections. PhdrEntry *Note = nullptr; - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; + for (OutputSection *Sec : OutputSections) { if (Sec->Type == SHT_NOTE) { - if (!Note || Cmd->LMAExpr) + if (!Note || Sec->LMAExpr) Note = AddHdr(PT_NOTE, PF_R); Note->add(Sec); } else { @@ -1538,18 +1710,18 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() { } template <class ELFT> -void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry> &Phdrs) { +void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry *> &Phdrs) { if (Config->EMachine != EM_ARM) return; - auto I = llvm::find_if(OutputSectionCommands, [](OutputSectionCommand *Cmd) { - return Cmd->Sec->Type == SHT_ARM_EXIDX; + auto I = llvm::find_if(OutputSections, [](OutputSection *Cmd) { + return Cmd->Type == SHT_ARM_EXIDX; }); - if (I == OutputSectionCommands.end()) + if (I == OutputSections.end()) return; // PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME - PhdrEntry ARMExidx(PT_ARM_EXIDX, PF_R); - ARMExidx.add((*I)->Sec); + PhdrEntry *ARMExidx = make<PhdrEntry>(PT_ARM_EXIDX, PF_R); + ARMExidx->add(*I); Phdrs.push_back(ARMExidx); } @@ -1557,33 +1729,31 @@ void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry> &Phdrs) { // first section after PT_GNU_RELRO have to be page aligned so that the dynamic // linker can set the permissions. template <class ELFT> void Writer<ELFT>::fixSectionAlignments() { - auto PageAlign = [](OutputSection *Sec) { - OutputSectionCommand *Cmd = Script->getCmd(Sec); + auto PageAlign = [](OutputSection *Cmd) { if (Cmd && !Cmd->AddrExpr) Cmd->AddrExpr = [=] { return alignTo(Script->getDot(), Config->MaxPageSize); }; }; - for (const PhdrEntry &P : Phdrs) - if (P.p_type == PT_LOAD && P.First) - PageAlign(P.First); + for (const PhdrEntry *P : Phdrs) + if (P->p_type == PT_LOAD && P->FirstSec) + PageAlign(P->FirstSec); - for (const PhdrEntry &P : Phdrs) { - if (P.p_type != PT_GNU_RELRO) + for (const PhdrEntry *P : Phdrs) { + if (P->p_type != PT_GNU_RELRO) continue; - if (P.First) - PageAlign(P.First); + if (P->FirstSec) + PageAlign(P->FirstSec); // Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we // have to align it to a page. - auto End = OutputSectionCommands.end(); - auto I = - std::find(OutputSectionCommands.begin(), End, Script->getCmd(P.Last)); + auto End = OutputSections.end(); + auto I = std::find(OutputSections.begin(), End, P->LastSec); if (I == End || (I + 1) == End) continue; - OutputSection *Sec = (*(I + 1))->Sec; - if (needsPtLoad(Sec)) - PageAlign(Sec); + OutputSection *Cmd = (*(I + 1)); + if (needsPtLoad(Cmd)) + PageAlign(Cmd); } } @@ -1591,40 +1761,39 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() { // its new file offset. The file offset must be the same with its // virtual address (modulo the page size) so that the loader can load // executables without any address adjustment. -static uint64_t getFileAlignment(uint64_t Off, OutputSection *Sec) { - OutputSection *First = Sec->FirstInPtLoad; +static uint64_t getFileAlignment(uint64_t Off, OutputSection *Cmd) { // If the section is not in a PT_LOAD, we just have to align it. - if (!First) - return alignTo(Off, Sec->Alignment); + if (!Cmd->PtLoad) + return alignTo(Off, Cmd->Alignment); + OutputSection *First = Cmd->PtLoad->FirstSec; // The first section in a PT_LOAD has to have congruent offset and address // module the page size. - if (Sec == First) - return alignTo(Off, Config->MaxPageSize, Sec->Addr); + if (Cmd == First) + return alignTo(Off, std::max<uint64_t>(Cmd->Alignment, Config->MaxPageSize), + Cmd->Addr); // If two sections share the same PT_LOAD the file offset is calculated // using this formula: Off2 = Off1 + (VA2 - VA1). - return First->Offset + Sec->Addr - First->Addr; + return First->Offset + Cmd->Addr - First->Addr; } -static uint64_t setOffset(OutputSection *Sec, uint64_t Off) { - if (Sec->Type == SHT_NOBITS) { - Sec->Offset = Off; +static uint64_t setOffset(OutputSection *Cmd, uint64_t Off) { + if (Cmd->Type == SHT_NOBITS) { + Cmd->Offset = Off; return Off; } - Off = getFileAlignment(Off, Sec); - Sec->Offset = Off; - return Off + Sec->Size; + Off = getFileAlignment(Off, Cmd); + Cmd->Offset = Off; + return Off + Cmd->Size; } template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() { uint64_t Off = 0; - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; + for (OutputSection *Sec : OutputSections) if (Sec->Flags & SHF_ALLOC) Off = setOffset(Sec, Off); - } FileSize = alignTo(Off, Config->Wordsize); } @@ -1634,46 +1803,58 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() { Off = setOffset(Out::ElfHeader, Off); Off = setOffset(Out::ProgramHeaders, Off); - for (OutputSectionCommand *Cmd : OutputSectionCommands) - Off = setOffset(Cmd->Sec, Off); + PhdrEntry *LastRX = nullptr; + for (PhdrEntry *P : Phdrs) + if (P->p_type == PT_LOAD && (P->p_flags & PF_X)) + LastRX = P; + + for (OutputSection *Sec : OutputSections) { + Off = setOffset(Sec, Off); + if (Script->HasSectionsCommand) + continue; + // If this is a last section of the last executable segment and that + // segment is the last loadable segment, align the offset of the + // following section to avoid loading non-segments parts of the file. + if (LastRX && LastRX->LastSec == Sec) + Off = alignTo(Off, Target->PageSize); + } SectionHeaderOff = alignTo(Off, Config->Wordsize); - FileSize = - SectionHeaderOff + (OutputSectionCommands.size() + 1) * sizeof(Elf_Shdr); + FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr); } // Finalize the program headers. We call this function after we assign // file offsets and VAs to all sections. template <class ELFT> void Writer<ELFT>::setPhdrs() { - for (PhdrEntry &P : Phdrs) { - OutputSection *First = P.First; - OutputSection *Last = P.Last; + for (PhdrEntry *P : Phdrs) { + OutputSection *First = P->FirstSec; + OutputSection *Last = P->LastSec; if (First) { - P.p_filesz = Last->Offset - First->Offset; + P->p_filesz = Last->Offset - First->Offset; if (Last->Type != SHT_NOBITS) - P.p_filesz += Last->Size; - P.p_memsz = Last->Addr + Last->Size - First->Addr; - P.p_offset = First->Offset; - P.p_vaddr = First->Addr; - if (!P.HasLMA) - P.p_paddr = First->getLMA(); + P->p_filesz += Last->Size; + P->p_memsz = Last->Addr + Last->Size - First->Addr; + P->p_offset = First->Offset; + P->p_vaddr = First->Addr; + if (!P->HasLMA) + P->p_paddr = First->getLMA(); } - if (P.p_type == PT_LOAD) - P.p_align = Config->MaxPageSize; - else if (P.p_type == PT_GNU_RELRO) { - P.p_align = 1; + if (P->p_type == PT_LOAD) + P->p_align = std::max<uint64_t>(P->p_align, Config->MaxPageSize); + else if (P->p_type == PT_GNU_RELRO) { + P->p_align = 1; // The glibc dynamic loader rounds the size down, so we need to round up // to protect the last page. This is a no-op on FreeBSD which always // rounds up. - P.p_memsz = alignTo(P.p_memsz, Target->PageSize); + P->p_memsz = alignTo(P->p_memsz, Target->PageSize); } // The TLS pointer goes after PT_TLS. At least glibc will align it, // so round up the size to make sure the offsets are correct. - if (P.p_type == PT_TLS) { - Out::TlsPhdr = &P; - if (P.p_memsz) - P.p_memsz = alignTo(P.p_memsz, P.p_align); + if (P->p_type == PT_TLS) { + Out::TlsPhdr = P; + if (P->p_memsz) + P->p_memsz = alignTo(P->p_memsz, P->p_align); } } } @@ -1682,27 +1863,29 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() { // // 1. the '-e' entry command-line option; // 2. the ENTRY(symbol) command in a linker control script; -// 3. the value of the symbol start, if present; -// 4. the address of the first byte of the .text section, if present; -// 5. the address 0. +// 3. the value of the symbol _start, if present; +// 4. the number represented by the entry symbol, if it is a number; +// 5. the address of the first byte of the .text section, if present; +// 6. the address 0. template <class ELFT> uint64_t Writer<ELFT>::getEntryAddr() { - // Case 1, 2 or 3. As a special case, if the symbol is actually - // a number, we'll use that number as an address. - if (SymbolBody *B = Symtab<ELFT>::X->find(Config->Entry)) + // Case 1, 2 or 3 + if (Symbol *B = Symtab->find(Config->Entry)) return B->getVA(); + + // Case 4 uint64_t Addr; if (to_integer(Config->Entry, Addr)) return Addr; - // Case 4 - if (OutputSection *Sec = findSectionInScript(".text")) { + // Case 5 + if (OutputSection *Sec = findSection(".text")) { if (Config->WarnMissingEntry) warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" + utohexstr(Sec->Addr)); return Sec->Addr; } - // Case 5 + // Case 6 if (Config->WarnMissingEntry) warn("cannot find entry symbol " + Config->Entry + "; not setting start address"); @@ -1717,64 +1900,6 @@ static uint16_t getELFType() { return ET_EXEC; } -// This function is called after we have assigned address and size -// to each section. This function fixes some predefined -// symbol values that depend on section address and size. -template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() { - // _etext is the first location after the last read-only loadable segment. - // _edata is the first location after the last read-write loadable segment. - // _end is the first location after the uninitialized data region. - PhdrEntry *Last = nullptr; - PhdrEntry *LastRO = nullptr; - PhdrEntry *LastRW = nullptr; - for (PhdrEntry &P : Phdrs) { - if (P.p_type != PT_LOAD) - continue; - Last = &P; - if (P.p_flags & PF_W) - LastRW = &P; - else - LastRO = &P; - } - - auto Set = [](DefinedRegular *S, OutputSection *Sec, uint64_t Value) { - if (S) { - S->Section = Sec; - S->Value = Value; - } - }; - - if (Last) { - Set(ElfSym::End1, Last->First, Last->p_memsz); - Set(ElfSym::End2, Last->First, Last->p_memsz); - } - if (LastRO) { - Set(ElfSym::Etext1, LastRO->First, LastRO->p_filesz); - Set(ElfSym::Etext2, LastRO->First, LastRO->p_filesz); - } - if (LastRW) { - Set(ElfSym::Edata1, LastRW->First, LastRW->p_filesz); - Set(ElfSym::Edata2, LastRW->First, LastRW->p_filesz); - } - - if (ElfSym::Bss) - ElfSym::Bss->Section = findSectionInScript(".bss"); - - // Setup MIPS _gp_disp/__gnu_local_gp symbols which should - // be equal to the _gp symbol's value. - if (Config->EMachine == EM_MIPS && !ElfSym::MipsGp->Value) { - // Find GP-relative section with the lowest address - // and use this address to calculate default _gp value. - for (const OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *OS = Cmd->Sec; - if (OS->Flags & SHF_MIPS_GPREL) { - ElfSym::MipsGp->Value = OS->Addr + 0x7ff0; - break; - } - } - } -} - template <class ELFT> void Writer<ELFT>::writeHeader() { uint8_t *Buf = Buffer->getBufferStart(); memcpy(Buf, "\177ELF", 4); @@ -1790,20 +1915,13 @@ template <class ELFT> void Writer<ELFT>::writeHeader() { EHdr->e_version = EV_CURRENT; EHdr->e_entry = getEntryAddr(); EHdr->e_shoff = SectionHeaderOff; + EHdr->e_flags = Config->EFlags; EHdr->e_ehsize = sizeof(Elf_Ehdr); EHdr->e_phnum = Phdrs.size(); EHdr->e_shentsize = sizeof(Elf_Shdr); - EHdr->e_shnum = OutputSectionCommands.size() + 1; + EHdr->e_shnum = OutputSections.size() + 1; EHdr->e_shstrndx = InX::ShStrTab->getParent()->SectionIndex; - if (Config->EMachine == EM_ARM) - // We don't currently use any features incompatible with EF_ARM_EABI_VER5, - // but we don't have any firm guarantees of conformance. Linux AArch64 - // kernels (as of 2016) require an EABI version to be set. - EHdr->e_flags = EF_ARM_EABI_VER5; - else if (Config->EMachine == EM_MIPS) - EHdr->e_flags = getMipsEFlags<ELFT>(); - if (!Config->Relocatable) { EHdr->e_phoff = sizeof(Elf_Ehdr); EHdr->e_phentsize = sizeof(Elf_Phdr); @@ -1811,22 +1929,22 @@ template <class ELFT> void Writer<ELFT>::writeHeader() { // Write the program header table. auto *HBuf = reinterpret_cast<Elf_Phdr *>(Buf + EHdr->e_phoff); - for (PhdrEntry &P : Phdrs) { - HBuf->p_type = P.p_type; - HBuf->p_flags = P.p_flags; - HBuf->p_offset = P.p_offset; - HBuf->p_vaddr = P.p_vaddr; - HBuf->p_paddr = P.p_paddr; - HBuf->p_filesz = P.p_filesz; - HBuf->p_memsz = P.p_memsz; - HBuf->p_align = P.p_align; + for (PhdrEntry *P : Phdrs) { + HBuf->p_type = P->p_type; + HBuf->p_flags = P->p_flags; + HBuf->p_offset = P->p_offset; + HBuf->p_vaddr = P->p_vaddr; + HBuf->p_paddr = P->p_paddr; + HBuf->p_filesz = P->p_filesz; + HBuf->p_memsz = P->p_memsz; + HBuf->p_align = P->p_align; ++HBuf; } // Write the section header table. Note that the first table entry is null. auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff); - for (OutputSectionCommand *Cmd : OutputSectionCommands) - Cmd->Sec->writeHeaderTo<ELFT>(++SHdrs); + for (OutputSection *Sec : OutputSections) + Sec->writeHeaderTo<ELFT>(++SHdrs); } // Open a result file. @@ -1837,23 +1955,58 @@ template <class ELFT> void Writer<ELFT>::openFile() { } unlinkAsync(Config->OutputFile); - ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr = - FileOutputBuffer::create(Config->OutputFile, FileSize, - FileOutputBuffer::F_executable); + unsigned Flags = 0; + if (!Config->Relocatable) + Flags = FileOutputBuffer::F_executable; + Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = + FileOutputBuffer::create(Config->OutputFile, FileSize, Flags); - if (auto EC = BufferOrErr.getError()) - error("failed to open " + Config->OutputFile + ": " + EC.message()); + if (!BufferOrErr) + error("failed to open " + Config->OutputFile + ": " + + llvm::toString(BufferOrErr.takeError())); else Buffer = std::move(*BufferOrErr); } template <class ELFT> void Writer<ELFT>::writeSectionsBinary() { uint8_t *Buf = Buffer->getBufferStart(); - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; + for (OutputSection *Sec : OutputSections) if (Sec->Flags & SHF_ALLOC) - Cmd->writeTo<ELFT>(Buf + Sec->Offset); - } + Sec->writeTo<ELFT>(Buf + Sec->Offset); +} + +static void fillTrap(uint8_t *I, uint8_t *End) { + for (; I + 4 <= End; I += 4) + memcpy(I, &Target->TrapInstr, 4); +} + +// Fill the last page of executable segments with trap instructions +// instead of leaving them as zero. Even though it is not required by any +// standard, it is in general a good thing to do for security reasons. +// +// We'll leave other pages in segments as-is because the rest will be +// overwritten by output sections. +template <class ELFT> void Writer<ELFT>::writeTrapInstr() { + if (Script->HasSectionsCommand) + return; + + // Fill the last page. + uint8_t *Buf = Buffer->getBufferStart(); + for (PhdrEntry *P : Phdrs) + if (P->p_type == PT_LOAD && (P->p_flags & PF_X)) + fillTrap(Buf + alignDown(P->p_offset + P->p_filesz, Target->PageSize), + Buf + alignTo(P->p_offset + P->p_filesz, Target->PageSize)); + + // Round up the file size of the last segment to the page boundary iff it is + // an executable segment to ensure that other tools don't accidentally + // trim the instruction padding (e.g. when stripping the file). + PhdrEntry *Last = nullptr; + for (PhdrEntry *P : Phdrs) + if (P->p_type == PT_LOAD) + Last = P; + + if (Last && (Last->p_flags & PF_X)) + Last->p_memsz = Last->p_filesz = alignTo(Last->p_filesz, Target->PageSize); } // Write section contents to a mmap'ed file. @@ -1862,39 +2015,32 @@ template <class ELFT> void Writer<ELFT>::writeSections() { // PPC64 needs to process relocations in the .opd section // before processing relocations in code-containing sections. - if (auto *OpdCmd = findSectionCommand(".opd")) { - Out::Opd = OpdCmd->Sec; + if (auto *OpdCmd = findSection(".opd")) { + Out::Opd = OpdCmd; Out::OpdBuf = Buf + Out::Opd->Offset; OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset); } - OutputSection *EhFrameHdr = - (In<ELFT>::EhFrameHdr && !In<ELFT>::EhFrameHdr->empty()) - ? In<ELFT>::EhFrameHdr->getParent() - : nullptr; + OutputSection *EhFrameHdr = nullptr; + if (InX::EhFrameHdr && !InX::EhFrameHdr->empty()) + EhFrameHdr = InX::EhFrameHdr->getParent(); // In -r or -emit-relocs mode, write the relocation sections first as in // ELf_Rel targets we might find out that we need to modify the relocated // section while doing it. - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; + for (OutputSection *Sec : OutputSections) if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) - Cmd->writeTo<ELFT>(Buf + Sec->Offset); - } + Sec->writeTo<ELFT>(Buf + Sec->Offset); - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; + for (OutputSection *Sec : OutputSections) if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA) - Cmd->writeTo<ELFT>(Buf + Sec->Offset); - } + Sec->writeTo<ELFT>(Buf + Sec->Offset); // The .eh_frame_hdr depends on .eh_frame section contents, therefore // it should be written after .eh_frame is written. - if (EhFrameHdr) { - OutputSectionCommand *Cmd = Script->getCmd(EhFrameHdr); - Cmd->writeTo<ELFT>(Buf + EhFrameHdr->Offset); - } + if (EhFrameHdr) + EhFrameHdr->writeTo<ELFT>(Buf + EhFrameHdr->Offset); } template <class ELFT> void Writer<ELFT>::writeBuildId() { @@ -1911,3 +2057,8 @@ template void elf::writeResult<ELF32LE>(); template void elf::writeResult<ELF32BE>(); template void elf::writeResult<ELF64LE>(); template void elf::writeResult<ELF64BE>(); + +template void elf::addReservedSymbols<ELF32LE>(); +template void elf::addReservedSymbols<ELF32BE>(); +template void elf::addReservedSymbols<ELF64LE>(); +template void elf::addReservedSymbols<ELF64BE>(); diff --git a/ELF/Writer.h b/ELF/Writer.h index 7fa56bea1c35..32d3c23047dd 100644 --- a/ELF/Writer.h +++ b/ELF/Writer.h @@ -20,11 +20,10 @@ namespace elf { class InputFile; class OutputSection; class InputSectionBase; -template <class ELFT> class ObjectFile; -template <class ELFT> class SymbolTable; +template <class ELFT> class ObjFile; +class SymbolTable; template <class ELFT> void writeResult(); template <class ELFT> void markLive(); -bool isRelroSection(const OutputSection *Sec); // This describes a program header entry. // Each contains type, access flags and range of output sections that will be @@ -42,19 +41,22 @@ struct PhdrEntry { uint32_t p_type = 0; uint32_t p_flags = 0; - OutputSection *First = nullptr; - OutputSection *Last = nullptr; + OutputSection *FirstSec = nullptr; + OutputSection *LastSec = nullptr; bool HasLMA = false; }; -llvm::StringRef getOutputSectionName(llvm::StringRef Name); +template <class ELFT> void addReservedSymbols(); +llvm::StringRef getOutputSectionName(InputSectionBase *S); -template <class ELFT> uint32_t getMipsEFlags(); +template <class ELFT> uint32_t calcMipsEFlags(); uint8_t getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag, llvm::StringRef FileName); bool isMipsN32Abi(const InputFile *F); +bool isMicroMips(); +bool isMipsR6(); } // namespace elf } // namespace lld |