aboutsummaryrefslogtreecommitdiff
path: root/ELF
diff options
context:
space:
mode:
Diffstat (limited to 'ELF')
-rw-r--r--ELF/AArch64ErrataFix.cpp648
-rw-r--r--ELF/AArch64ErrataFix.h52
-rw-r--r--ELF/Arch/AArch64.cpp94
-rw-r--r--ELF/Arch/AMDGPU.cpp34
-rw-r--r--ELF/Arch/ARM.cpp189
-rw-r--r--ELF/Arch/AVR.cpp18
-rw-r--r--ELF/Arch/Mips.cpp463
-rw-r--r--ELF/Arch/MipsArchTree.cpp54
-rw-r--r--ELF/Arch/PPC.cpp36
-rw-r--r--ELF/Arch/PPC64.cpp16
-rw-r--r--ELF/Arch/SPARCV9.cpp13
-rw-r--r--ELF/Arch/X86.cpp137
-rw-r--r--ELF/Arch/X86_64.cpp46
-rw-r--r--ELF/Bits.h35
-rw-r--r--ELF/CMakeLists.txt17
-rw-r--r--ELF/Config.h40
-rw-r--r--ELF/Driver.cpp485
-rw-r--r--ELF/Driver.h5
-rw-r--r--ELF/DriverUtils.cpp68
-rw-r--r--ELF/EhFrame.cpp42
-rw-r--r--ELF/EhFrame.h6
-rw-r--r--ELF/Error.cpp116
-rw-r--r--ELF/Error.h78
-rw-r--r--ELF/Filesystem.cpp45
-rw-r--r--ELF/Filesystem.h3
-rw-r--r--ELF/GdbIndex.cpp88
-rw-r--r--ELF/GdbIndex.h89
-rw-r--r--ELF/ICF.cpp99
-rw-r--r--ELF/InputFiles.cpp541
-rw-r--r--ELF/InputFiles.h105
-rw-r--r--ELF/InputSection.cpp461
-rw-r--r--ELF/InputSection.h199
-rw-r--r--ELF/LTO.cpp63
-rw-r--r--ELF/LTO.h4
-rw-r--r--ELF/LinkerScript.cpp1381
-rw-r--r--ELF/LinkerScript.h211
-rw-r--r--ELF/MapFile.cpp95
-rw-r--r--ELF/MapFile.h6
-rw-r--r--ELF/MarkLive.cpp191
-rw-r--r--ELF/Memory.h67
-rw-r--r--ELF/Options.td177
-rw-r--r--ELF/OutputSections.cpp488
-rw-r--r--ELF/OutputSections.h109
-rw-r--r--ELF/Relocations.cpp1078
-rw-r--r--ELF/Relocations.h64
-rw-r--r--ELF/ScriptLexer.cpp44
-rw-r--r--ELF/ScriptLexer.h3
-rw-r--r--ELF/ScriptParser.cpp302
-rw-r--r--ELF/ScriptParser.h5
-rw-r--r--ELF/Strings.cpp31
-rw-r--r--ELF/Strings.h6
-rw-r--r--ELF/SymbolTable.cpp631
-rw-r--r--ELF/SymbolTable.h99
-rw-r--r--ELF/Symbols.cpp253
-rw-r--r--ELF/Symbols.h399
-rw-r--r--ELF/SyntheticSections.cpp1632
-rw-r--r--ELF/SyntheticSections.h351
-rw-r--r--ELF/Target.cpp34
-rw-r--r--ELF/Target.h111
-rw-r--r--ELF/Threads.h88
-rw-r--r--ELF/Thunks.cpp237
-rw-r--r--ELF/Thunks.h18
-rw-r--r--ELF/Writer.cpp1609
-rw-r--r--ELF/Writer.h16
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