aboutsummaryrefslogtreecommitdiff
path: root/lld/ELF
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF')
-rw-r--r--lld/ELF/AArch64ErrataFix.cpp4
-rw-r--r--lld/ELF/ARMErrataFix.cpp4
-rw-r--r--lld/ELF/Arch/ARM.cpp202
-rw-r--r--lld/ELF/Arch/Hexagon.cpp2
-rw-r--r--lld/ELF/Arch/RISCV.cpp2
-rw-r--r--lld/ELF/Arch/X86.cpp9
-rw-r--r--lld/ELF/Arch/X86_64.cpp60
-rw-r--r--lld/ELF/Config.h19
-rw-r--r--lld/ELF/Driver.cpp45
-rw-r--r--lld/ELF/ICF.cpp8
-rw-r--r--lld/ELF/InputFiles.cpp56
-rw-r--r--lld/ELF/InputFiles.h28
-rw-r--r--lld/ELF/InputSection.cpp4
-rw-r--r--lld/ELF/InputSection.h16
-rw-r--r--lld/ELF/LTO.cpp2
-rw-r--r--lld/ELF/LinkerScript.cpp301
-rw-r--r--lld/ELF/LinkerScript.h59
-rw-r--r--lld/ELF/MapFile.cpp96
-rw-r--r--lld/ELF/MapFile.h3
-rw-r--r--lld/ELF/Options.td30
-rw-r--r--lld/ELF/OutputSections.cpp48
-rw-r--r--lld/ELF/OutputSections.h7
-rw-r--r--lld/ELF/Relocations.cpp72
-rw-r--r--lld/ELF/ScriptParser.cpp70
-rw-r--r--lld/ELF/SymbolTable.cpp2
-rw-r--r--lld/ELF/Symbols.cpp41
-rw-r--r--lld/ELF/Symbols.h6
-rw-r--r--lld/ELF/SyntheticSections.cpp156
-rw-r--r--lld/ELF/SyntheticSections.h15
-rw-r--r--lld/ELF/Thunks.cpp64
-rw-r--r--lld/ELF/Writer.cpp244
-rw-r--r--lld/ELF/Writer.h1
32 files changed, 780 insertions, 896 deletions
diff --git a/lld/ELF/AArch64ErrataFix.cpp b/lld/ELF/AArch64ErrataFix.cpp
index b9fd4cdbad69..741ff26a7e6c 100644
--- a/lld/ELF/AArch64ErrataFix.cpp
+++ b/lld/ELF/AArch64ErrataFix.cpp
@@ -630,8 +630,8 @@ bool AArch64Err843419Patcher::createFixes() {
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)) {
+ for (SectionCommand *cmd : os->commands)
+ if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) {
std::vector<Patch843419Section *> patches =
patchInputSectionDescription(*isd);
if (!patches.empty()) {
diff --git a/lld/ELF/ARMErrataFix.cpp b/lld/ELF/ARMErrataFix.cpp
index 77623780ffa5..fe6ec09bd979 100644
--- a/lld/ELF/ARMErrataFix.cpp
+++ b/lld/ELF/ARMErrataFix.cpp
@@ -525,8 +525,8 @@ bool ARMErr657417Patcher::createFixes() {
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)) {
+ for (SectionCommand *cmd : os->commands)
+ if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) {
std::vector<Patch657417Section *> patches =
patchInputSectionDescription(*isd);
if (!patches.empty()) {
diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp
index f2e4a2a14ad6..b7c2eb74757c 100644
--- a/lld/ELF/Arch/ARM.cpp
+++ b/lld/ELF/Arch/ARM.cpp
@@ -140,7 +140,16 @@ RelExpr ARM::getRelExpr(RelType type, const Symbol &s,
case R_ARM_THM_MOVT_PREL:
return R_PC;
case R_ARM_ALU_PC_G0:
+ case R_ARM_ALU_PC_G0_NC:
+ case R_ARM_ALU_PC_G1:
+ case R_ARM_ALU_PC_G1_NC:
+ case R_ARM_ALU_PC_G2:
case R_ARM_LDR_PC_G0:
+ case R_ARM_LDR_PC_G1:
+ case R_ARM_LDR_PC_G2:
+ case R_ARM_LDRS_PC_G0:
+ case R_ARM_LDRS_PC_G1:
+ case R_ARM_LDRS_PC_G2:
case R_ARM_THM_ALU_PREL_11_0:
case R_ARM_THM_PC8:
case R_ARM_THM_PC12:
@@ -411,56 +420,83 @@ static void stateChangeWarning(uint8_t *loc, RelType relt, const Symbol &s) {
}
}
-// Utility functions taken from ARMAddressingModes.h, only changes are LLD
-// coding style.
-
// Rotate a 32-bit unsigned value right by a specified amt of bits.
static uint32_t rotr32(uint32_t val, uint32_t amt) {
assert(amt < 32 && "Invalid rotate amount");
return (val >> amt) | (val << ((32 - amt) & 31));
}
-// Rotate a 32-bit unsigned value left by a specified amt of bits.
-static uint32_t rotl32(uint32_t val, uint32_t amt) {
- assert(amt < 32 && "Invalid rotate amount");
- return (val << amt) | (val >> ((32 - amt) & 31));
+static std::pair<uint32_t, uint32_t> getRemAndLZForGroup(unsigned group,
+ uint32_t val) {
+ uint32_t rem, lz;
+ do {
+ lz = llvm::countLeadingZeros(val) & ~1;
+ rem = val;
+ if (lz == 32) // implies rem == 0
+ break;
+ val &= 0xffffff >> lz;
+ } while (group--);
+ return {rem, lz};
}
-// Try to encode a 32-bit unsigned immediate imm with an immediate shifter
-// operand, this form is an 8-bit immediate rotated right by an even number of
-// bits. We compute the rotate amount to use. If this immediate value cannot be
-// handled with a single shifter-op, determine a good rotate amount that will
-// take a maximal chunk of bits out of the immediate.
-static uint32_t getSOImmValRotate(uint32_t imm) {
- // 8-bit (or less) immediates are trivially shifter_operands with a rotate
- // of zero.
- if ((imm & ~255U) == 0)
- return 0;
-
- // Use CTZ to compute the rotate amount.
- unsigned tz = llvm::countTrailingZeros(imm);
-
- // Rotate amount must be even. Something like 0x200 must be rotated 8 bits,
- // not 9.
- unsigned rotAmt = tz & ~1;
-
- // If we can handle this spread, return it.
- if ((rotr32(imm, rotAmt) & ~255U) == 0)
- return (32 - rotAmt) & 31; // HW rotates right, not left.
+static void encodeAluGroup(uint8_t *loc, const Relocation &rel, uint64_t val,
+ int group, bool check) {
+ // ADD/SUB (immediate) add = bit23, sub = bit22
+ // immediate field carries is a 12-bit modified immediate, made up of a 4-bit
+ // even rotate right and an 8-bit immediate.
+ uint32_t opcode = 0x00800000;
+ if (val >> 63) {
+ opcode = 0x00400000;
+ val = -val;
+ }
+ uint32_t imm, lz;
+ std::tie(imm, lz) = getRemAndLZForGroup(group, val);
+ uint32_t rot = 0;
+ if (lz < 24) {
+ imm = rotr32(imm, 24 - lz);
+ rot = (lz + 8) << 7;
+ }
+ if (check && imm > 0xff)
+ error(getErrorLocation(loc) + "unencodeable immediate " + Twine(val).str() +
+ " for relocation " + toString(rel.type));
+ write32le(loc, (read32le(loc) & 0xff3ff000) | opcode | rot | (imm & 0xff));
+}
- // For values like 0xF000000F, we should ignore the low 6 bits, then
- // retry the hunt.
- if (imm & 63U) {
- unsigned tz2 = countTrailingZeros(imm & ~63U);
- unsigned rotAmt2 = tz2 & ~1;
- if ((rotr32(imm, rotAmt2) & ~255U) == 0)
- return (32 - rotAmt2) & 31; // HW rotates right, not left.
+static void encodeLdrGroup(uint8_t *loc, const Relocation &rel, uint64_t val,
+ int group) {
+ // R_ARM_LDR_PC_Gn is S + A - P, we have ((S + A) | T) - P, if S is a
+ // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear
+ // bottom bit to recover S + A - P.
+ if (rel.sym->isFunc())
+ val &= ~0x1;
+ // LDR (literal) u = bit23
+ uint32_t opcode = 0x00800000;
+ if (val >> 63) {
+ opcode = 0x0;
+ val = -val;
}
+ uint32_t imm = getRemAndLZForGroup(group, val).first;
+ checkUInt(loc, imm, 12, rel);
+ write32le(loc, (read32le(loc) & 0xff7ff000) | opcode | imm);
+}
- // Otherwise, we have no way to cover this span of bits with a single
- // shifter_op immediate. Return a chunk of bits that will be useful to
- // handle.
- return (32 - rotAmt) & 31; // HW rotates right, not left.
+static void encodeLdrsGroup(uint8_t *loc, const Relocation &rel, uint64_t val,
+ int group) {
+ // R_ARM_LDRS_PC_Gn is S + A - P, we have ((S + A) | T) - P, if S is a
+ // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear
+ // bottom bit to recover S + A - P.
+ if (rel.sym->isFunc())
+ val &= ~0x1;
+ // LDRD/LDRH/LDRSB/LDRSH (literal) u = bit23
+ uint32_t opcode = 0x00800000;
+ if (val >> 63) {
+ opcode = 0x0;
+ val = -val;
+ }
+ uint32_t imm = getRemAndLZForGroup(group, val).first;
+ checkUInt(loc, imm, 8, rel);
+ write32le(loc, (read32le(loc) & 0xff7ff0f0) | opcode | ((imm & 0xf0) << 4) |
+ (imm & 0xf));
}
void ARM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
@@ -633,45 +669,39 @@ void ARM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
((val << 4) & 0x7000) | // imm3
(val & 0x00ff)); // imm8
break;
- case R_ARM_ALU_PC_G0: {
- // ADR (literal) add = bit23, sub = bit22
- // literal is a 12-bit modified immediate, made up of a 4-bit even rotate
- // right and an 8-bit immediate. The code-sequence here is derived from
- // ARMAddressingModes.h in llvm/Target/ARM/MCTargetDesc. In our case we
- // want to give an error if we cannot encode the constant.
- uint32_t opcode = 0x00800000;
- if (val >> 63) {
- opcode = 0x00400000;
- val = ~val + 1;
- }
- if ((val & ~255U) != 0) {
- uint32_t rotAmt = getSOImmValRotate(val);
- // Error if we cannot encode this with a single shift
- if (rotr32(~255U, rotAmt) & val)
- error(getErrorLocation(loc) + "unencodeable immediate " +
- Twine(val).str() + " for relocation " + toString(rel.type));
- val = rotl32(val, rotAmt) | ((rotAmt >> 1) << 8);
- }
- write32le(loc, (read32le(loc) & 0xff0ff000) | opcode | val);
+ case R_ARM_ALU_PC_G0:
+ encodeAluGroup(loc, rel, val, 0, true);
break;
- }
- case R_ARM_LDR_PC_G0: {
- // R_ARM_LDR_PC_G0 is S + A - P, we have ((S + A) | T) - P, if S is a
- // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear
- // bottom bit to recover S + A - P.
- if (rel.sym->isFunc())
- val &= ~0x1;
- // LDR (literal) u = bit23
- int64_t imm = val;
- uint32_t u = 0x00800000;
- if (imm < 0) {
- imm = -imm;
- u = 0;
- }
- checkUInt(loc, imm, 12, rel);
- write32le(loc, (read32le(loc) & 0xff7ff000) | u | imm);
+ case R_ARM_ALU_PC_G0_NC:
+ encodeAluGroup(loc, rel, val, 0, false);
+ break;
+ case R_ARM_ALU_PC_G1:
+ encodeAluGroup(loc, rel, val, 1, true);
+ break;
+ case R_ARM_ALU_PC_G1_NC:
+ encodeAluGroup(loc, rel, val, 1, false);
+ break;
+ case R_ARM_ALU_PC_G2:
+ encodeAluGroup(loc, rel, val, 2, true);
+ break;
+ case R_ARM_LDR_PC_G0:
+ encodeLdrGroup(loc, rel, val, 0);
+ break;
+ case R_ARM_LDR_PC_G1:
+ encodeLdrGroup(loc, rel, val, 1);
+ break;
+ case R_ARM_LDR_PC_G2:
+ encodeLdrGroup(loc, rel, val, 2);
+ break;
+ case R_ARM_LDRS_PC_G0:
+ encodeLdrsGroup(loc, rel, val, 0);
+ break;
+ case R_ARM_LDRS_PC_G1:
+ encodeLdrsGroup(loc, rel, val, 1);
+ break;
+ case R_ARM_LDRS_PC_G2:
+ encodeLdrsGroup(loc, rel, val, 2);
break;
- }
case R_ARM_THM_ALU_PREL_11_0: {
// ADR encoding T2 (sub), T3 (add) i:imm3:imm8
int64_t imm = val;
@@ -816,7 +846,11 @@ int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const {
((lo & 0x7000) >> 4) | // imm3
(lo & 0x00ff)); // imm8
}
- case R_ARM_ALU_PC_G0: {
+ case R_ARM_ALU_PC_G0:
+ case R_ARM_ALU_PC_G0_NC:
+ case R_ARM_ALU_PC_G1:
+ case R_ARM_ALU_PC_G1_NC:
+ case R_ARM_ALU_PC_G2: {
// 12-bit immediate is a modified immediate made up of a 4-bit even
// right rotation and 8-bit constant. After the rotation the value
// is zero-extended. When bit 23 is set the instruction is an add, when
@@ -825,13 +859,25 @@ int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const {
uint32_t val = rotr32(instr & 0xff, ((instr & 0xf00) >> 8) * 2);
return (instr & 0x00400000) ? -val : val;
}
- case R_ARM_LDR_PC_G0: {
+ case R_ARM_LDR_PC_G0:
+ case R_ARM_LDR_PC_G1:
+ case R_ARM_LDR_PC_G2: {
// ADR (literal) add = bit23, sub = bit22
// LDR (literal) u = bit23 unsigned imm12
bool u = read32le(buf) & 0x00800000;
uint32_t imm12 = read32le(buf) & 0xfff;
return u ? imm12 : -imm12;
}
+ case R_ARM_LDRS_PC_G0:
+ case R_ARM_LDRS_PC_G1:
+ case R_ARM_LDRS_PC_G2: {
+ // LDRD/LDRH/LDRSB/LDRSH (literal) u = bit23 unsigned imm8
+ uint32_t opcode = read32le(buf);
+ bool u = opcode & 0x00800000;
+ uint32_t imm4l = opcode & 0xf;
+ uint32_t imm4h = (opcode & 0xf00) >> 4;
+ return u ? (imm4h | imm4l) : -(imm4h | imm4l);
+ }
case R_ARM_THM_ALU_PREL_11_0: {
// Thumb2 ADR, which is an alias for a sub or add instruction with an
// unsigned immediate.
diff --git a/lld/ELF/Arch/Hexagon.cpp b/lld/ELF/Arch/Hexagon.cpp
index 300ca675519f..c33bd935f363 100644
--- a/lld/ELF/Arch/Hexagon.cpp
+++ b/lld/ELF/Arch/Hexagon.cpp
@@ -146,7 +146,7 @@ RelExpr Hexagon::getRelExpr(RelType type, const Symbol &s,
case R_HEX_IE_GOT_32_6_X:
case R_HEX_IE_GOT_HI16:
case R_HEX_IE_GOT_LO16:
- config->hasStaticTlsModel = true;
+ config->hasTlsIe = true;
return R_GOTPLT;
case R_HEX_TPREL_11_X:
case R_HEX_TPREL_16:
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 5ee9e4185f1a..a0ea403e241d 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -261,7 +261,7 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
case R_RISCV_TLS_GD_HI20:
return R_TLSGD_PC;
case R_RISCV_TLS_GOT_HI20:
- config->hasStaticTlsModel = true;
+ config->hasTlsIe = true;
return R_GOT_PC;
case R_RISCV_TPREL_HI20:
case R_RISCV_TPREL_LO12_I:
diff --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp
index 5d34b769e80e..2560dc883257 100644
--- a/lld/ELF/Arch/X86.cpp
+++ b/lld/ELF/Arch/X86.cpp
@@ -78,13 +78,8 @@ int X86::getTlsGdRelaxSkip(RelType type) const {
RelExpr X86::getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const {
- // There are 4 different TLS variable models with varying degrees of
- // flexibility and performance. LocalExec and InitialExec models are fast but
- // less-flexible models. If they are in use, we set DF_STATIC_TLS flag in the
- // dynamic section to let runtime know about that.
- if (type == R_386_TLS_LE || type == R_386_TLS_LE_32 || type == R_386_TLS_IE ||
- type == R_386_TLS_GOTIE)
- config->hasStaticTlsModel = true;
+ if (type == R_386_TLS_IE || type == R_386_TLS_GOTIE)
+ config->hasTlsIe = true;
switch (type) {
case R_386_8:
diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp
index 40436752399b..614b5ed59218 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -99,7 +99,11 @@ X86_64::X86_64() {
defaultImageBase = 0x200000;
}
-int X86_64::getTlsGdRelaxSkip(RelType type) const { return 2; }
+int X86_64::getTlsGdRelaxSkip(RelType type) const {
+ // TLSDESC relocations are processed separately. See relaxTlsGdToLe below.
+ return type == R_X86_64_GOTPC32_TLSDESC || type == R_X86_64_TLSDESC_CALL ? 1
+ : 2;
+}
// Opcodes for the different X86_64 jmp instructions.
enum JmpInsnOpcode : uint32_t {
@@ -314,7 +318,7 @@ bool X86_64::deleteFallThruJmpInsn(InputSection &is, InputFile *file,
RelExpr X86_64::getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const {
if (type == R_X86_64_GOTTPOFF)
- config->hasStaticTlsModel = true;
+ config->hasTlsIe = true;
switch (type) {
case R_X86_64_8:
@@ -443,24 +447,24 @@ void X86_64::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
// The original code used a pc relative relocation and so we have to
// compensate for the -4 in had in the addend.
write32le(loc + 8, val + 4);
- } else {
- // Convert
- // lea x@tlsgd(%rip), %rax
- // call *(%rax)
- // to the following two instructions.
- assert(rel.type == R_X86_64_GOTPC32_TLSDESC);
- if (memcmp(loc - 3, "\x48\x8d\x05", 3)) {
- error(getErrorLocation(loc - 3) + "R_X86_64_GOTPC32_TLSDESC must be used "
- "in callq *x@tlsdesc(%rip), %rax");
+ } else if (rel.type == R_X86_64_GOTPC32_TLSDESC) {
+ // Convert leaq x@tlsdesc(%rip), %REG to movq $x@tpoff, %REG.
+ if ((loc[-3] & 0xfb) != 0x48 || loc[-2] != 0x8d ||
+ (loc[-1] & 0xc7) != 0x05) {
+ errorOrWarn(getErrorLocation(loc - 3) +
+ "R_X86_64_GOTPC32_TLSDESC must be used "
+ "in leaq x@tlsdesc(%rip), %REG");
return;
}
- // movq $x@tpoff(%rip),%rax
+ loc[-3] = 0x48 | ((loc[-3] >> 2) & 1);
loc[-2] = 0xc7;
- loc[-1] = 0xc0;
+ loc[-1] = 0xc0 | ((loc[-1] >> 3) & 7);
write32le(loc, val + 4);
- // xchg ax,ax
- loc[4] = 0x66;
- loc[5] = 0x90;
+ } else {
+ // Convert call *x@tlsdesc(%REG) to xchg ax, ax.
+ assert(rel.type == R_X86_64_TLSDESC_CALL);
+ loc[0] = 0x66;
+ loc[1] = 0x90;
}
}
@@ -484,23 +488,23 @@ void X86_64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
// Both code sequences are PC relatives, but since we are moving the
// constant forward by 8 bytes we have to subtract the value by 8.
write32le(loc + 8, val - 8);
- } else {
- // Convert
- // lea x@tlsgd(%rip), %rax
- // call *(%rax)
- // to the following two instructions.
+ } else if (rel.type == R_X86_64_GOTPC32_TLSDESC) {
+ // Convert leaq x@tlsdesc(%rip), %REG to movq x@gottpoff(%rip), %REG.
assert(rel.type == R_X86_64_GOTPC32_TLSDESC);
- if (memcmp(loc - 3, "\x48\x8d\x05", 3)) {
- error(getErrorLocation(loc - 3) + "R_X86_64_GOTPC32_TLSDESC must be used "
- "in callq *x@tlsdesc(%rip), %rax");
+ if ((loc[-3] & 0xfb) != 0x48 || loc[-2] != 0x8d ||
+ (loc[-1] & 0xc7) != 0x05) {
+ errorOrWarn(getErrorLocation(loc - 3) +
+ "R_X86_64_GOTPC32_TLSDESC must be used "
+ "in leaq x@tlsdesc(%rip), %REG");
return;
}
- // movq x@gottpoff(%rip),%rax
loc[-2] = 0x8b;
write32le(loc, val);
- // xchg ax,ax
- loc[4] = 0x66;
- loc[5] = 0x90;
+ } else {
+ // Convert call *x@tlsdesc(%rax) to xchg ax, ax.
+ assert(rel.type == R_X86_64_TLSDESC_CALL);
+ loc[0] = 0x66;
+ loc[1] = 0x90;
}
}
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 79c4fe06d7b2..c660a8e67c21 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -261,7 +261,7 @@ struct Configuration {
UnresolvedPolicy unresolvedSymbols;
UnresolvedPolicy unresolvedSymbolsInShlib;
Target2Policy target2;
- bool Power10Stub;
+ bool power10Stubs;
ARMVFPArgKind armVFPArgs = ARMVFPArgKind::Default;
BuildIdKind buildId = BuildIdKind::None;
SeparateSegmentKind zSeparate;
@@ -309,19 +309,10 @@ struct Configuration {
// if that's true.)
bool isMips64EL;
- // True if we need to set the DF_STATIC_TLS flag to an output file,
- // which works as a hint to the dynamic loader that the file contains
- // code compiled with the static TLS model. The thread-local variable
- // compiled with the static TLS model is faster but less flexible, and
- // it may not be loaded using dlopen().
- //
- // We set this flag to true when we see a relocation for the static TLS
- // model. Once this becomes true, it will never become false.
- //
- // Since the flag is updated by multi-threaded code, we use std::atomic.
- // (Writing to a variable is not considered thread-safe even if the
- // variable is boolean and we always set the same value from all threads.)
- std::atomic<bool> hasStaticTlsModel{false};
+ // True if we need to set the DF_STATIC_TLS flag to an output file, which
+ // works as a hint to the dynamic loader that the shared object contains code
+ // compiled with the initial-exec TLS model.
+ bool hasTlsIe = false;
// Holds set of ELF header flags for the target.
uint32_t eflags = 0;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 9fac04558c46..1376e6c2c253 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -460,19 +460,21 @@ static bool isKnownZFlag(StringRef s) {
s.startswith("start-stop-visibility=");
}
-// Report an error for an unknown -z option.
+// Report a warning for an unknown -z option.
static void checkZOptions(opt::InputArgList &args) {
for (auto *arg : args.filtered(OPT_z))
if (!isKnownZFlag(arg->getValue()))
- error("unknown -z value: " + StringRef(arg->getValue()));
+ warn("unknown -z value: " + StringRef(arg->getValue()));
}
void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
ELFOptTable parser;
opt::InputArgList args = parser.parse(argsArr.slice(1));
- // Interpret this flag early because error() depends on them.
+ // Interpret the flags early because error()/warn() depend on them.
errorHandler().errorLimit = args::getInteger(args, OPT_error_limit, 20);
+ errorHandler().fatalWarnings =
+ args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
checkZOptions(args);
// Handle -help
@@ -750,20 +752,6 @@ static OrphanHandlingPolicy getOrphanHandling(opt::InputArgList &args) {
return OrphanHandlingPolicy::Place;
}
-// Parses --power10-stubs= flags, to disable or enable Power 10
-// instructions in stubs.
-static bool getP10StubOpt(opt::InputArgList &args) {
-
- if (args.getLastArgValue(OPT_power10_stubs_eq)== "no")
- return false;
-
- if (!args.hasArg(OPT_power10_stubs_eq) &&
- args.hasArg(OPT_no_power10_stubs))
- return false;
-
- return true;
-}
-
// Parse --build-id or --build-id=<style>. We handle "tree" as a
// synonym for "sha1" because all our hash functions including
// --build-id=sha1 are actually tree hashes for performance reasons.
@@ -985,8 +973,6 @@ static void parseClangOption(StringRef opt, const Twine &msg) {
// Initializes Config members by the command line options.
static void readConfigs(opt::InputArgList &args) {
errorHandler().verbose = args.hasArg(OPT_verbose);
- errorHandler().fatalWarnings =
- args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
errorHandler().vsDiagnostics =
args.hasArg(OPT_visual_studio_diagnostics_format, false);
@@ -1190,7 +1176,7 @@ static void readConfigs(opt::InputArgList &args) {
config->zText = getZFlag(args, "text", "notext", true);
config->zWxneeded = hasZOption(args, "wxneeded");
setUnresolvedSymbolPolicy(args);
- config->Power10Stub = getP10StubOpt(args);
+ config->power10Stubs = args.getLastArgValue(OPT_power10_stubs_eq) != "no";
if (opt::Arg *arg = args.getLastArg(OPT_eb, OPT_el)) {
if (arg->getOption().matches(OPT_eb))
@@ -1691,7 +1677,7 @@ static void handleUndefined(Symbol *sym, const char *option) {
if (!sym->isLazy())
return;
- sym->fetch();
+ sym->extract();
if (!config->whyExtract.empty())
whyExtract.emplace_back(option, sym->file, *sym);
}
@@ -1706,14 +1692,12 @@ static void handleUndefinedGlob(StringRef arg) {
return;
}
+ // Calling sym->extract() in the loop is not safe because it may add new
+ // symbols to the symbol table, invalidating the current iterator.
std::vector<Symbol *> syms;
- for (Symbol *sym : symtab->symbols()) {
- // Calling Sym->fetch() from here is not safe because it may
- // add new symbols to the symbol table, invalidating the
- // current iterator. So we just keep a note.
+ for (Symbol *sym : symtab->symbols())
if (pat->match(sym->getName()))
syms.push_back(sym);
- }
for (Symbol *sym : syms)
handleUndefined(sym, "--undefined-glob");
@@ -1731,7 +1715,7 @@ static void handleLibcall(StringRef name) {
mb = cast<LazyArchive>(sym)->getMemberBuffer();
if (isBitcode(mb))
- sym->fetch();
+ sym->extract();
}
// Handle --dependency-file=<path>. If that option is given, lld creates a
@@ -2207,7 +2191,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
symtab->insert(arg->getValue())->traced = true;
// Handle -u/--undefined before input files. If both a.a and b.so define foo,
- // -u foo a.a b.so will fetch a.a.
+ // -u foo a.a b.so will extract a.a.
for (StringRef name : config->undefined)
addUnusedUndefined(name)->referenced = true;
@@ -2297,7 +2281,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// 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);
std::vector<WrappedSymbol> wrapped = addWrappedSymbols(args);
@@ -2476,8 +2459,8 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// merging MergeInputSections into a single MergeSyntheticSection. From this
// point onwards InputSectionDescription::sections should be used instead of
// sectionBases.
- for (BaseCommand *base : script->sectionCommands)
- if (auto *sec = dyn_cast<OutputSection>(base))
+ for (SectionCommand *cmd : script->sectionCommands)
+ if (auto *sec = dyn_cast<OutputSection>(cmd))
sec->finalizeInputSections();
llvm::erase_if(inputSections, [](InputSectionBase *s) {
return isa<MergeInputSection>(s);
diff --git a/lld/ELF/ICF.cpp b/lld/ELF/ICF.cpp
index c13969806916..0ec748e8f990 100644
--- a/lld/ELF/ICF.cpp
+++ b/lld/ELF/ICF.cpp
@@ -552,10 +552,10 @@ template <class ELFT> void ICF<ELFT>::run() {
// InputSectionDescription::sections is populated by processSectionCommands().
// ICF may fold some input sections assigned to output sections. Remove them.
- for (BaseCommand *base : script->sectionCommands)
- if (auto *sec = dyn_cast<OutputSection>(base))
- for (BaseCommand *sub_base : sec->sectionCommands)
- if (auto *isd = dyn_cast<InputSectionDescription>(sub_base))
+ for (SectionCommand *cmd : script->sectionCommands)
+ if (auto *sec = dyn_cast<OutputSection>(cmd))
+ for (SectionCommand *subCmd : sec->commands)
+ if (auto *isd = dyn_cast<InputSectionDescription>(subCmd))
llvm::erase_if(isd->sections,
[](InputSection *isec) { return !isec->isLive(); });
}
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index e8a4188ec775..031a8679db41 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -395,16 +395,6 @@ uint32_t ObjFile<ELFT>::getSectionIndex(const Elf_Sym &sym) const {
this);
}
-template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getLocalSymbols() {
- if (this->symbols.empty())
- return {};
- return makeArrayRef(this->symbols).slice(1, this->firstGlobal - 1);
-}
-
-template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getGlobalSymbols() {
- return makeArrayRef(this->symbols).slice(this->firstGlobal);
-}
-
template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
// Read a section table. justSymbols is usually false.
if (this->justSymbols)
@@ -966,7 +956,7 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(uint32_t idx,
// `nullptr` for the normal case. However, if -r or --emit-relocs is
// specified, we need to copy them to the output. (Some post link analysis
// tools specify --emit-relocs to obtain the information.)
- if (!config->relocatable && !config->emitRelocs)
+ if (!config->copyRelocs)
return nullptr;
InputSection *relocSec = make<InputSection>(*this, sec, name);
// If the relocated section is discarded (due to /DISCARD/ or
@@ -1035,12 +1025,11 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(uint32_t idx,
name == ".gnu.linkonce.t.__i686.get_pc_thunk.bx")
return &InputSection::discarded;
- // If we are creating a new .build-id section, strip existing .build-id
- // sections so that the output won't have more than one .build-id.
- // This is not usually a problem because input object files normally don't
- // have .build-id sections, but you can create such files by
- // "ld.{bfd,gold,lld} -r --build-id", and we want to guard against it.
- if (name == ".note.gnu.build-id" && config->buildId != BuildIdKind::None)
+ // Strip existing .note.gnu.build-id sections so that the output won't have
+ // more than one build-id. This is not usually a problem because input object
+ // files normally don't have .build-id sections, but you can create such files
+ // by "ld.{bfd,gold,lld} -r --build-id", and we want to guard against it.
+ if (name == ".note.gnu.build-id")
return &InputSection::discarded;
// The linker merges EH (exception handling) frames and creates a
@@ -1147,17 +1136,20 @@ template <class ELFT> void ObjFile<ELFT>::initializeSymbols() {
if (sec == &InputSection::discarded) {
Undefined und{this, name, binding, stOther, type, secIdx};
Symbol *sym = this->symbols[i];
- // !ArchiveFile::parsed or LazyObjFile::fetched means that the file
+ // !ArchiveFile::parsed or LazyObjFile::extracted means that the file
// containing this object has not finished processing, i.e. this symbol is
- // a result of a lazy symbol fetch. We should demote the lazy symbol to an
- // Undefined so that any relocations outside of the group to it will
+ // a result of a lazy symbol extract. We should demote the lazy symbol to
+ // an Undefined so that any relocations outside of the group to it will
// trigger a discarded section error.
if ((sym->symbolKind == Symbol::LazyArchiveKind &&
!cast<ArchiveFile>(sym->file)->parsed) ||
(sym->symbolKind == Symbol::LazyObjectKind &&
- cast<LazyObjFile>(sym->file)->fetched))
+ cast<LazyObjFile>(sym->file)->extracted)) {
sym->replace(und);
- else
+ // Prevent LTO from internalizing the symbol in case there is a
+ // reference to this symbol from this file.
+ sym->isUsedInRegularObj = true;
+ } else
sym->resolve(und);
continue;
}
@@ -1174,7 +1166,7 @@ template <class ELFT> void ObjFile<ELFT>::initializeSymbols() {
}
// Undefined symbols (excluding those defined relative to non-prevailing
- // sections) can trigger recursive fetch. Process defined symbols first so
+ // sections) can trigger recursive extract. Process defined symbols first so
// that the relative order between a defined symbol and an undefined symbol
// does not change the symbol resolution behavior. In addition, a set of
// interconnected symbols will all be resolved to the same file, instead of
@@ -1202,7 +1194,7 @@ void ArchiveFile::parse() {
}
// Returns a buffer pointing to a member file containing a given symbol.
-void ArchiveFile::fetch(const Archive::Symbol &sym) {
+void ArchiveFile::extract(const Archive::Symbol &sym) {
Archive::Child c =
CHECK(sym.getMember(), toString(this) +
": could not get the member for symbol " +
@@ -1291,7 +1283,7 @@ static bool isNonCommonDef(MemoryBufferRef mb, StringRef symName,
}
}
-bool ArchiveFile::shouldFetchForCommon(const Archive::Symbol &sym) {
+bool ArchiveFile::shouldExtractForCommon(const Archive::Symbol &sym) {
Archive::Child c =
CHECK(sym.getMember(), toString(this) +
": could not get the member for symbol " +
@@ -1779,10 +1771,10 @@ InputFile *elf::createObjectFile(MemoryBufferRef mb, StringRef archiveName,
}
}
-void LazyObjFile::fetch() {
- if (fetched)
+void LazyObjFile::extract() {
+ if (extracted)
return;
- fetched = true;
+ extracted = true;
InputFile *file = createObjectFile(mb, archiveName, offsetInArchive);
file->groupId = groupId;
@@ -1835,7 +1827,7 @@ template <class ELFT> void LazyObjFile::parse() {
// Replace existing symbols with LazyObject symbols.
//
- // resolve() may trigger this->fetch() if an existing symbol is an
+ // resolve() may trigger this->extract() if an existing symbol is an
// undefined symbol. If that happens, this LazyObjFile has served
// its purpose, and we can exit from the loop early.
for (Symbol *sym : this->symbols) {
@@ -1843,16 +1835,16 @@ template <class ELFT> void LazyObjFile::parse() {
continue;
sym->resolve(LazyObject{*this, sym->getName()});
- // If fetched, stop iterating because this->symbols has been transferred
+ // If extracted, stop iterating because this->symbols has been transferred
// to the instantiated ObjFile.
- if (fetched)
+ if (extracted)
return;
}
return;
}
}
-bool LazyObjFile::shouldFetchForCommon(const StringRef &name) {
+bool LazyObjFile::shouldExtractForCommon(const StringRef &name) {
if (isBitcode(mb))
return isBitcodeNonCommonDef(mb, name, archiveName);
diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h
index fb4d46b43f35..5bbfb7656e47 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -168,6 +168,15 @@ public:
StringRef getStringTable() const { return stringTable; }
+ ArrayRef<Symbol *> getLocalSymbols() {
+ if (symbols.empty())
+ return {};
+ return llvm::makeArrayRef(symbols).slice(1, firstGlobal - 1);
+ }
+ ArrayRef<Symbol *> getGlobalSymbols() {
+ return llvm::makeArrayRef(symbols).slice(firstGlobal);
+ }
+
template <typename ELFT> typename ELFT::SymRange getELFSyms() const {
return typename ELFT::SymRange(
reinterpret_cast<const typename ELFT::Sym *>(elfSyms), numELFSyms);
@@ -197,9 +206,6 @@ public:
return this->ELFFileBase::getObj<ELFT>();
}
- ArrayRef<Symbol *> getLocalSymbols();
- ArrayRef<Symbol *> getGlobalSymbols();
-
ObjFile(MemoryBufferRef m, StringRef archiveName) : ELFFileBase(ObjKind, m) {
this->archiveName = std::string(archiveName);
}
@@ -306,13 +312,13 @@ public:
static bool classof(const InputFile *f) { return f->kind() == LazyObjKind; }
template <class ELFT> void parse();
- void fetch();
+ void extract();
- // Check if a non-common symbol should be fetched to override a common
+ // Check if a non-common symbol should be extracted to override a common
// definition.
- bool shouldFetchForCommon(const StringRef &name);
+ bool shouldExtractForCommon(const StringRef &name);
- bool fetched = false;
+ bool extracted = false;
private:
uint64_t offsetInArchive;
@@ -329,14 +335,14 @@ public:
// returns it. If the same file was instantiated before, this
// function does nothing (so we don't instantiate the same file
// more than once.)
- void fetch(const Archive::Symbol &sym);
+ void extract(const Archive::Symbol &sym);
- // Check if a non-common symbol should be fetched to override a common
+ // Check if a non-common symbol should be extracted to override a common
// definition.
- bool shouldFetchForCommon(const Archive::Symbol &sym);
+ bool shouldExtractForCommon(const Archive::Symbol &sym);
size_t getMemberCount() const;
- size_t getFetchedMemberCount() const { return seen.size(); }
+ size_t getExtractedMemberCount() const { return seen.size(); }
bool parsed = false;
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 74d4dd309c79..4d5bd1f1e5f2 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -187,7 +187,7 @@ uint64_t SectionBase::getOffset(uint64_t offset) const {
}
case Regular:
case Synthetic:
- return cast<InputSection>(this)->getOffset(offset);
+ return cast<InputSection>(this)->outSecOff + offset;
case EHFrame:
// The file crtbeginT.o has relocations pointing to the start of an empty
// .eh_frame that is known to be the first in the link. It does that to
@@ -196,7 +196,7 @@ uint64_t SectionBase::getOffset(uint64_t offset) const {
case Merge:
const MergeInputSection *ms = cast<MergeInputSection>(this);
if (InputSection *isec = ms->getParent())
- return isec->getOffset(ms->getParentOffset(offset));
+ return isec->outSecOff + ms->getParentOffset(offset);
return ms->getParentOffset(offset);
}
llvm_unreachable("invalid section kind");
diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h
index 4bd1f410e388..7ddc43916a0f 100644
--- a/lld/ELF/InputSection.h
+++ b/lld/ELF/InputSection.h
@@ -78,7 +78,7 @@ public:
// These corresponds to the fields in Elf_Shdr.
uint32_t alignment;
uint64_t flags;
- uint64_t entsize;
+ uint32_t entsize;
uint32_t type;
uint32_t link;
uint32_t info;
@@ -99,9 +99,9 @@ public:
void markDead() { partition = 0; }
protected:
- SectionBase(Kind sectionKind, StringRef name, uint64_t flags,
- uint64_t entsize, uint64_t alignment, uint32_t type,
- uint32_t info, uint32_t link)
+ constexpr SectionBase(Kind sectionKind, StringRef name, uint64_t flags,
+ uint32_t entsize, uint32_t alignment, uint32_t type,
+ uint32_t info, uint32_t link)
: name(name), repl(this), sectionKind(sectionKind), bss(false),
keepUnique(false), partition(0), alignment(alignment), flags(flags),
entsize(entsize), type(type), link(link), info(info) {}
@@ -121,14 +121,14 @@ public:
static bool classof(const SectionBase *s) { return s->kind() != Output; }
- // Section index of the relocation section if exists.
- uint32_t relSecIdx = 0;
-
// The file which contains this section. Its dynamic type is always
// ObjFile<ELFT>, but in order to avoid ELFT, we use InputFile as
// its static type.
InputFile *file;
+ // Section index of the relocation section if exists.
+ uint32_t relSecIdx = 0;
+
template <class ELFT> ObjFile<ELFT> *getFile() const {
return cast_or_null<ObjFile<ELFT>>(file);
}
@@ -352,8 +352,6 @@ public:
// beginning of the output section.
template <class ELFT> void writeTo(uint8_t *buf);
- uint64_t getOffset(uint64_t offset) const { return outSecOff + offset; }
-
OutputSection *getParent() const;
// This variable has two usages. Initially, it represents an index in the
diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp
index a42d216e4e77..46dc77a6789c 100644
--- a/lld/ELF/LTO.cpp
+++ b/lld/ELF/LTO.cpp
@@ -279,7 +279,7 @@ void BitcodeCompiler::add(BitcodeFile &f) {
// distributed build system that depends on that behavior.
static void thinLTOCreateEmptyIndexFiles() {
for (LazyObjFile *f : lazyObjFiles) {
- if (f->fetched || !isBitcode(f->mb))
+ if (f->extracted || !isBitcode(f->mb))
continue;
std::string path = replaceThinLTOSuffix(getThinLTOOutputFile(f->getName()));
std::unique_ptr<raw_fd_ostream> os = openFile(path + ".thinlto.bc");
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index f332b03d757d..cf4da7ab54c9 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -49,23 +49,76 @@ using namespace lld::elf;
LinkerScript *elf::script;
-static uint64_t getOutputSectionVA(SectionBase *sec) {
- OutputSection *os = sec->getOutputSection();
- assert(os && "input section has no output section assigned");
- return os ? os->addr : 0;
+static bool isSectionPrefix(StringRef prefix, StringRef name) {
+ return name.startswith(prefix) || name == prefix.drop_back();
+}
+
+static StringRef getOutputSectionName(const InputSectionBase *s) {
+ if (config->relocatable)
+ 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 (auto *isec = dyn_cast<InputSection>(s)) {
+ if (InputSectionBase *rel = isec->getRelocatedSection()) {
+ OutputSection *out = rel->getOutputSection();
+ if (s->type == SHT_RELA)
+ return saver.save(".rela" + out->name);
+ return saver.save(".rel" + out->name);
+ }
+ }
+
+ // A BssSection created for a common symbol is identified as "COMMON" in
+ // linker scripts. It should go to .bss section.
+ if (s->name == "COMMON")
+ return ".bss";
+
+ if (script->hasSectionsCommand)
+ return s->name;
+
+ // When no SECTIONS is specified, emulate GNU ld's internal linker scripts
+ // by grouping sections with certain prefixes.
+
+ // GNU ld places text sections with prefix ".text.hot.", ".text.unknown.",
+ // ".text.unlikely.", ".text.startup." or ".text.exit." before others.
+ // We provide an option -z keep-text-section-prefix to group such sections
+ // into separate output sections. This is more flexible. See also
+ // sortISDBySectionOrder().
+ // ".text.unknown" means the hotness of the section is unknown. When
+ // SampleFDO is used, if a function doesn't have sample, it could be very
+ // cold or it could be a new function never being sampled. Those functions
+ // will be kept in the ".text.unknown" section.
+ // ".text.split." holds symbols which are split out from functions in other
+ // input sections. For example, with -fsplit-machine-functions, placing the
+ // cold parts in .text.split instead of .text.unlikely mitigates against poor
+ // profile inaccuracy. Techniques such as hugepage remapping can make
+ // conservative decisions at the section granularity.
+ if (config->zKeepTextSectionPrefix)
+ for (StringRef v : {".text.hot.", ".text.unknown.", ".text.unlikely.",
+ ".text.startup.", ".text.exit.", ".text.split."})
+ if (isSectionPrefix(v, s->name))
+ return v.drop_back();
+
+ 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."})
+ if (isSectionPrefix(v, s->name))
+ return v.drop_back();
+
+ return s->name;
}
uint64_t ExprValue::getValue() const {
if (sec)
- return alignTo(sec->getOffset(val) + getOutputSectionVA(sec),
+ return alignTo(sec->getOutputSection()->addr + sec->getOffset(val),
alignment);
return alignTo(val, alignment);
}
uint64_t ExprValue::getSecAddr() const {
- if (sec)
- return sec->getOffset(0) + getOutputSectionVA(sec);
- return 0;
+ return sec ? sec->getOutputSection()->addr + sec->getOffset(0) : 0;
}
uint64_t ExprValue::getSectionOffset() const {
@@ -102,23 +155,22 @@ OutputSection *LinkerScript::getOrCreateOutputSection(StringRef name) {
// Expands the memory region by the specified size.
static void expandMemoryRegion(MemoryRegion *memRegion, uint64_t size,
- StringRef regionName, StringRef secName) {
+ StringRef secName) {
memRegion->curPos += size;
uint64_t newSize = memRegion->curPos - (memRegion->origin)().getValue();
uint64_t length = (memRegion->length)().getValue();
if (newSize > length)
- error("section '" + secName + "' will not fit in region '" + regionName +
- "': overflowed by " + Twine(newSize - length) + " bytes");
+ error("section '" + secName + "' will not fit in region '" +
+ memRegion->name + "': overflowed by " + Twine(newSize - length) +
+ " bytes");
}
void LinkerScript::expandMemoryRegions(uint64_t size) {
if (ctx->memRegion)
- expandMemoryRegion(ctx->memRegion, size, ctx->memRegion->name,
- ctx->outSec->name);
+ expandMemoryRegion(ctx->memRegion, size, ctx->outSec->name);
// Only expand the LMARegion if it is different from memRegion.
if (ctx->lmaRegion && ctx->memRegion != ctx->lmaRegion)
- expandMemoryRegion(ctx->lmaRegion, size, ctx->lmaRegion->name,
- ctx->outSec->name);
+ expandMemoryRegion(ctx->lmaRegion, size, ctx->outSec->name);
}
void LinkerScript::expandOutputSection(uint64_t size) {
@@ -215,21 +267,21 @@ using SymbolAssignmentMap =
// Collect section/value pairs of linker-script-defined symbols. This is used to
// check whether symbol values converge.
-static SymbolAssignmentMap
-getSymbolAssignmentValues(const std::vector<BaseCommand *> &sectionCommands) {
+static SymbolAssignmentMap getSymbolAssignmentValues(
+ const std::vector<SectionCommand *> &sectionCommands) {
SymbolAssignmentMap ret;
- for (BaseCommand *base : sectionCommands) {
- if (auto *cmd = dyn_cast<SymbolAssignment>(base)) {
- if (cmd->sym) // sym is nullptr for dot.
- ret.try_emplace(cmd->sym,
- std::make_pair(cmd->sym->section, cmd->sym->value));
+ for (SectionCommand *cmd : sectionCommands) {
+ if (auto *assign = dyn_cast<SymbolAssignment>(cmd)) {
+ if (assign->sym) // sym is nullptr for dot.
+ ret.try_emplace(assign->sym, std::make_pair(assign->sym->section,
+ assign->sym->value));
continue;
}
- for (BaseCommand *sub_base : cast<OutputSection>(base)->sectionCommands)
- if (auto *cmd = dyn_cast<SymbolAssignment>(sub_base))
- if (cmd->sym)
- ret.try_emplace(cmd->sym,
- std::make_pair(cmd->sym->section, cmd->sym->value));
+ for (SectionCommand *subCmd : cast<OutputSection>(cmd)->commands)
+ if (auto *assign = dyn_cast<SymbolAssignment>(subCmd))
+ if (assign->sym)
+ ret.try_emplace(assign->sym, std::make_pair(assign->sym->section,
+ assign->sym->value));
}
return ret;
}
@@ -256,9 +308,9 @@ void LinkerScript::processInsertCommands() {
for (StringRef name : cmd.names) {
// If base is empty, it may have been discarded by
// adjustSectionsBeforeSorting(). We do not handle such output sections.
- auto from = llvm::find_if(sectionCommands, [&](BaseCommand *base) {
- return isa<OutputSection>(base) &&
- cast<OutputSection>(base)->name == name;
+ auto from = llvm::find_if(sectionCommands, [&](SectionCommand *subCmd) {
+ return isa<OutputSection>(subCmd) &&
+ cast<OutputSection>(subCmd)->name == name;
});
if (from == sectionCommands.end())
continue;
@@ -266,10 +318,11 @@ void LinkerScript::processInsertCommands() {
sectionCommands.erase(from);
}
- auto insertPos = llvm::find_if(sectionCommands, [&cmd](BaseCommand *base) {
- auto *to = dyn_cast<OutputSection>(base);
- return to != nullptr && to->name == cmd.where;
- });
+ auto insertPos =
+ llvm::find_if(sectionCommands, [&cmd](SectionCommand *subCmd) {
+ auto *to = dyn_cast<OutputSection>(subCmd);
+ return to != nullptr && to->name == cmd.where;
+ });
if (insertPos == sectionCommands.end()) {
error("unable to insert " + cmd.names[0] +
(cmd.isAfter ? " after " : " before ") + cmd.where);
@@ -287,9 +340,9 @@ void LinkerScript::processInsertCommands() {
// over symbol assignment commands and create placeholder symbols if needed.
void LinkerScript::declareSymbols() {
assert(!ctx);
- for (BaseCommand *base : sectionCommands) {
- if (auto *cmd = dyn_cast<SymbolAssignment>(base)) {
- declareSymbol(cmd);
+ for (SectionCommand *cmd : sectionCommands) {
+ if (auto *assign = dyn_cast<SymbolAssignment>(cmd)) {
+ declareSymbol(assign);
continue;
}
@@ -297,12 +350,12 @@ void LinkerScript::declareSymbols() {
// we can't say for sure if it is going to be included or not.
// Skip such sections for now. Improve the checks if we ever
// need symbols from that sections to be declared early.
- auto *sec = cast<OutputSection>(base);
+ auto *sec = cast<OutputSection>(cmd);
if (sec->constraint != ConstraintKind::NoConstraint)
continue;
- for (BaseCommand *base2 : sec->sectionCommands)
- if (auto *cmd = dyn_cast<SymbolAssignment>(base2))
- declareSymbol(cmd);
+ for (SectionCommand *cmd : sec->commands)
+ if (auto *assign = dyn_cast<SymbolAssignment>(cmd))
+ declareSymbol(assign);
}
}
@@ -528,10 +581,10 @@ void LinkerScript::discardSynthetic(OutputSection &outCmd) {
continue;
std::vector<InputSectionBase *> secs(part.armExidx->exidxSections.begin(),
part.armExidx->exidxSections.end());
- for (BaseCommand *base : outCmd.sectionCommands)
- if (auto *cmd = dyn_cast<InputSectionDescription>(base)) {
+ for (SectionCommand *cmd : outCmd.commands)
+ if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) {
std::vector<InputSectionBase *> matches =
- computeInputSections(cmd, secs);
+ computeInputSections(isd, secs);
for (InputSectionBase *s : matches)
discard(s);
}
@@ -542,12 +595,12 @@ std::vector<InputSectionBase *>
LinkerScript::createInputSectionList(OutputSection &outCmd) {
std::vector<InputSectionBase *> ret;
- for (BaseCommand *base : outCmd.sectionCommands) {
- if (auto *cmd = dyn_cast<InputSectionDescription>(base)) {
- cmd->sectionBases = computeInputSections(cmd, inputSections);
- for (InputSectionBase *s : cmd->sectionBases)
+ for (SectionCommand *cmd : outCmd.commands) {
+ if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) {
+ isd->sectionBases = computeInputSections(isd, inputSections);
+ for (InputSectionBase *s : isd->sectionBases)
s->parent = &outCmd;
- ret.insert(ret.end(), cmd->sectionBases.begin(), cmd->sectionBases.end());
+ ret.insert(ret.end(), isd->sectionBases.begin(), isd->sectionBases.end());
}
}
return ret;
@@ -564,7 +617,7 @@ void LinkerScript::processSectionCommands() {
for (InputSectionBase *s : v)
discard(s);
discardSynthetic(*osec);
- osec->sectionCommands.clear();
+ osec->commands.clear();
return false;
}
@@ -578,7 +631,7 @@ void LinkerScript::processSectionCommands() {
if (!matchConstraints(v, osec->constraint)) {
for (InputSectionBase *s : v)
s->parent = nullptr;
- osec->sectionCommands.clear();
+ osec->commands.clear();
return false;
}
@@ -605,7 +658,7 @@ void LinkerScript::processSectionCommands() {
for (OutputSection *osec : overwriteSections)
if (process(osec) && !map.try_emplace(osec->name, osec).second)
warn("OVERWRITE_SECTIONS specifies duplicate " + osec->name);
- for (BaseCommand *&base : sectionCommands)
+ for (SectionCommand *&base : sectionCommands)
if (auto *osec = dyn_cast<OutputSection>(base)) {
if (OutputSection *overwrite = map.lookup(osec->name)) {
log(overwrite->location + " overwrites " + osec->name);
@@ -639,22 +692,22 @@ void LinkerScript::processSymbolAssignments() {
ctx = &state;
ctx->outSec = aether;
- for (BaseCommand *base : sectionCommands) {
- if (auto *cmd = dyn_cast<SymbolAssignment>(base))
- addSymbol(cmd);
+ for (SectionCommand *cmd : sectionCommands) {
+ if (auto *assign = dyn_cast<SymbolAssignment>(cmd))
+ addSymbol(assign);
else
- for (BaseCommand *sub_base : cast<OutputSection>(base)->sectionCommands)
- if (auto *cmd = dyn_cast<SymbolAssignment>(sub_base))
- addSymbol(cmd);
+ for (SectionCommand *subCmd : cast<OutputSection>(cmd)->commands)
+ if (auto *assign = dyn_cast<SymbolAssignment>(subCmd))
+ addSymbol(assign);
}
ctx = nullptr;
}
-static OutputSection *findByName(ArrayRef<BaseCommand *> vec,
+static OutputSection *findByName(ArrayRef<SectionCommand *> vec,
StringRef name) {
- for (BaseCommand *base : vec)
- if (auto *sec = dyn_cast<OutputSection>(base))
+ for (SectionCommand *cmd : vec)
+ if (auto *sec = dyn_cast<OutputSection>(cmd))
if (sec->name == name)
return sec;
return nullptr;
@@ -753,8 +806,7 @@ addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map,
// end up being linked to the same output section. The casts are fine
// because everything in the map was created by the orphan placement code.
auto *firstIsec = cast<InputSectionBase>(
- cast<InputSectionDescription>(sec->sectionCommands[0])
- ->sectionBases[0]);
+ cast<InputSectionDescription>(sec->commands[0])->sectionBases[0]);
OutputSection *firstIsecOut =
firstIsec->flags & SHF_LINK_ORDER
? firstIsec->getLinkOrderDep()->getOutputSection()
@@ -848,38 +900,6 @@ void LinkerScript::diagnoseOrphanHandling() const {
}
}
-uint64_t LinkerScript::advance(uint64_t size, unsigned alignment) {
- dot = alignTo(dot, alignment) + size;
- return dot;
-}
-
-void LinkerScript::output(InputSection *s) {
- assert(ctx->outSec == s->getParent());
- uint64_t before = advance(0, 1);
- uint64_t pos = advance(s->getSize(), s->alignment);
- 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) }
- expandOutputSection(pos - before);
-}
-
-void LinkerScript::switchTo(OutputSection *sec) {
- ctx->outSec = sec;
-
- uint64_t pos = advance(0, 1);
- if (sec->addrExpr && script->hasSectionsCommand) {
- // The alignment is ignored.
- ctx->outSec->addr = pos;
- } else {
- // ctx->outSec->alignment is the max of ALIGN and the maximum of input
- // section alignments.
- ctx->outSec->addr = advance(0, ctx->outSec->alignment);
- expandMemoryRegions(ctx->outSec->addr - pos);
- }
-}
-
// 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 in the first member of the pair. Otherwise, a nullptr is returned.
@@ -917,7 +937,7 @@ LinkerScript::findMemoryRegion(OutputSection *sec, MemoryRegion *hint) {
// See if a region can be found by matching section flags.
for (auto &pair : memoryRegions) {
MemoryRegion *m = pair.second;
- if ((m->flags & sec->flags) && (m->negFlags & sec->flags) == 0)
+ if (m->compatibleWith(sec->flags))
return {m, nullptr};
}
@@ -965,10 +985,21 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
// between the previous section, if any, and the start of this section.
if (ctx->memRegion && ctx->memRegion->curPos < dot)
expandMemoryRegion(ctx->memRegion, dot - ctx->memRegion->curPos,
- ctx->memRegion->name, sec->name);
+ sec->name);
}
- switchTo(sec);
+ ctx->outSec = sec;
+ if (sec->addrExpr && script->hasSectionsCommand) {
+ // The alignment is ignored.
+ sec->addr = dot;
+ } else {
+ // sec->alignment is the max of ALIGN and the maximum of input
+ // section alignments.
+ const uint64_t pos = dot;
+ dot = alignTo(dot, sec->alignment);
+ sec->addr = dot;
+ expandMemoryRegions(dot - pos);
+ }
// ctx->lmaOffset is LMA minus VMA. If LMA is explicitly specified via AT() or
// AT>, recompute ctx->lmaOffset; otherwise, if both previous/current LMA
@@ -981,14 +1012,14 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
} else if (MemoryRegion *mr = sec->lmaRegion) {
uint64_t lmaStart = alignTo(mr->curPos, sec->alignment);
if (mr->curPos < lmaStart)
- expandMemoryRegion(mr, lmaStart - mr->curPos, mr->name, sec->name);
+ expandMemoryRegion(mr, lmaStart - mr->curPos, sec->name);
ctx->lmaOffset = lmaStart - dot;
} else if (!sameMemRegion || !prevLMARegionIsDefault) {
ctx->lmaOffset = 0;
}
// Propagate ctx->lmaOffset to the first "non-header" section.
- if (PhdrEntry *l = ctx->outSec->ptLoad)
+ if (PhdrEntry *l = sec->ptLoad)
if (sec == findFirstSection(l))
l->lmaOffset = ctx->lmaOffset;
@@ -999,28 +1030,38 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
// We visited SectionsCommands from processSectionCommands to
// layout sections. Now, we visit SectionsCommands again to fix
// section offsets.
- for (BaseCommand *base : sec->sectionCommands) {
+ for (SectionCommand *cmd : sec->commands) {
// This handles the assignments to symbol or to the dot.
- if (auto *cmd = dyn_cast<SymbolAssignment>(base)) {
- cmd->addr = dot;
- assignSymbol(cmd, true);
- cmd->size = dot - cmd->addr;
+ if (auto *assign = dyn_cast<SymbolAssignment>(cmd)) {
+ assign->addr = dot;
+ assignSymbol(assign, true);
+ assign->size = dot - assign->addr;
continue;
}
// Handle BYTE(), SHORT(), LONG(), or QUAD().
- if (auto *cmd = dyn_cast<ByteCommand>(base)) {
- cmd->offset = dot - ctx->outSec->addr;
- dot += cmd->size;
- expandOutputSection(cmd->size);
+ if (auto *data = dyn_cast<ByteCommand>(cmd)) {
+ data->offset = dot - sec->addr;
+ dot += data->size;
+ expandOutputSection(data->size);
continue;
}
// Handle a single input section description command.
// It calculates and assigns the offsets for each section and also
// updates the output section size.
- for (InputSection *sec : cast<InputSectionDescription>(base)->sections)
- output(sec);
+ for (InputSection *isec : cast<InputSectionDescription>(cmd)->sections) {
+ assert(isec->getParent() == sec);
+ const uint64_t pos = dot;
+ dot = alignTo(dot, isec->alignment);
+ isec->outSecOff = dot - sec->addr;
+ dot += isec->getSize();
+
+ // 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) }
+ expandOutputSection(dot - pos);
+ }
}
// Non-SHF_ALLOC sections do not affect the addresses of other OutputSections
@@ -1050,14 +1091,14 @@ static bool isDiscardable(const OutputSection &sec) {
if (sec.usedInExpression)
return false;
- for (BaseCommand *base : sec.sectionCommands) {
- if (auto cmd = dyn_cast<SymbolAssignment>(base))
+ for (SectionCommand *cmd : sec.commands) {
+ if (auto assign = dyn_cast<SymbolAssignment>(cmd))
// Don't create empty output sections just for unreferenced PROVIDE
// symbols.
- if (cmd->name != "." && !cmd->sym)
+ if (assign->name != "." && !assign->sym)
continue;
- if (!isa<InputSectionDescription>(*base))
+ if (!isa<InputSectionDescription>(*cmd))
return false;
}
return true;
@@ -1104,7 +1145,7 @@ void LinkerScript::adjustSectionsBeforeSorting() {
uint64_t flags = SHF_ALLOC;
std::vector<StringRef> defPhdrs;
- for (BaseCommand *&cmd : sectionCommands) {
+ for (SectionCommand *&cmd : sectionCommands) {
auto *sec = dyn_cast<OutputSection>(cmd);
if (!sec)
continue;
@@ -1150,14 +1191,14 @@ void LinkerScript::adjustSectionsBeforeSorting() {
// clutter the output.
// We instead remove trivially empty sections. The bfd linker seems even
// more aggressive at removing them.
- llvm::erase_if(sectionCommands, [&](BaseCommand *base) { return !base; });
+ llvm::erase_if(sectionCommands, [&](SectionCommand *cmd) { return !cmd; });
}
void LinkerScript::adjustSectionsAfterSorting() {
// Try and find an appropriate memory region to assign offsets in.
MemoryRegion *hint = nullptr;
- for (BaseCommand *base : sectionCommands) {
- if (auto *sec = dyn_cast<OutputSection>(base)) {
+ for (SectionCommand *cmd : sectionCommands) {
+ if (auto *sec = dyn_cast<OutputSection>(cmd)) {
if (!sec->lmaRegionName.empty()) {
if (MemoryRegion *m = memoryRegions.lookup(sec->lmaRegionName))
sec->lmaRegion = m;
@@ -1183,8 +1224,8 @@ void LinkerScript::adjustSectionsAfterSorting() {
// Walk the commands and propagate the program headers to commands that don't
// explicitly specify them.
- for (BaseCommand *base : sectionCommands)
- if (auto *sec = dyn_cast<OutputSection>(base))
+ for (SectionCommand *cmd : sectionCommands)
+ if (auto *sec = dyn_cast<OutputSection>(cmd))
maybePropagatePhdrs(*sec, defPhdrs);
}
@@ -1267,20 +1308,20 @@ const Defined *LinkerScript::assignAddresses() {
dot += getHeaderSize();
}
- auto deleter = std::make_unique<AddressState>();
- ctx = deleter.get();
+ AddressState state;
+ ctx = &state;
errorOnMissingSection = true;
- switchTo(aether);
+ ctx->outSec = aether;
SymbolAssignmentMap oldValues = getSymbolAssignmentValues(sectionCommands);
- for (BaseCommand *base : sectionCommands) {
- if (auto *cmd = dyn_cast<SymbolAssignment>(base)) {
- cmd->addr = dot;
- assignSymbol(cmd, false);
- cmd->size = dot - cmd->addr;
+ for (SectionCommand *cmd : sectionCommands) {
+ if (auto *assign = dyn_cast<SymbolAssignment>(cmd)) {
+ assign->addr = dot;
+ assignSymbol(assign, false);
+ assign->size = dot - assign->addr;
continue;
}
- assignOffsets(cast<OutputSection>(base));
+ assignOffsets(cast<OutputSection>(cmd));
}
ctx = nullptr;
diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h
index b366da4f274e..badc4d126be8 100644
--- a/lld/ELF/LinkerScript.h
+++ b/lld/ELF/LinkerScript.h
@@ -41,7 +41,7 @@ class ThunkSection;
struct ExprValue {
ExprValue(SectionBase *sec, bool forceAbsolute, uint64_t val,
const Twine &loc)
- : sec(sec), forceAbsolute(forceAbsolute), val(val), loc(loc.str()) {}
+ : sec(sec), val(val), forceAbsolute(forceAbsolute), loc(loc.str()) {}
ExprValue(uint64_t val) : ExprValue(nullptr, false, val, "") {}
@@ -53,10 +53,6 @@ struct ExprValue {
// 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;
@@ -64,6 +60,10 @@ struct ExprValue {
// resets type to STT_NOTYPE.
uint8_t type = llvm::ELF::STT_NOTYPE;
+ // True if this expression is enclosed in ABSOLUTE().
+ // This flag affects the return value of getValue().
+ bool forceAbsolute;
+
// Original source location. Used for error messages.
std::string loc;
};
@@ -82,17 +82,18 @@ enum SectionsCommandKind {
ByteKind // BYTE(expr), SHORT(expr), LONG(expr) or QUAD(expr)
};
-struct BaseCommand {
- BaseCommand(int k) : kind(k) {}
+struct SectionCommand {
+ SectionCommand(int k) : kind(k) {}
int kind;
};
// This represents ". = <expr>" or "<symbol> = <expr>".
-struct SymbolAssignment : BaseCommand {
+struct SymbolAssignment : SectionCommand {
SymbolAssignment(StringRef name, Expr e, std::string loc)
- : BaseCommand(AssignmentKind), name(name), expression(e), location(loc) {}
+ : SectionCommand(AssignmentKind), name(name), expression(e),
+ location(loc) {}
- static bool classof(const BaseCommand *c) {
+ static bool classof(const SectionCommand *c) {
return c->kind == AssignmentKind;
}
@@ -132,16 +133,32 @@ enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite };
// MEMORY command.
struct MemoryRegion {
MemoryRegion(StringRef name, Expr origin, Expr length, uint32_t flags,
- uint32_t negFlags)
+ uint32_t invFlags, uint32_t negFlags, uint32_t negInvFlags)
: name(std::string(name)), origin(origin), length(length), flags(flags),
- negFlags(negFlags) {}
+ invFlags(invFlags), negFlags(negFlags), negInvFlags(negInvFlags) {}
std::string name;
Expr origin;
Expr length;
+ // A section can be assigned to the region if any of these ELF section flags
+ // are set...
uint32_t flags;
+ // ... or any of these flags are not set.
+ // For example, the memory region attribute "r" maps to SHF_WRITE.
+ uint32_t invFlags;
+ // A section cannot be assigned to the region if any of these ELF section
+ // flags are set...
uint32_t negFlags;
+ // ... or any of these flags are not set.
+ // For example, the memory region attribute "!r" maps to SHF_WRITE.
+ uint32_t negInvFlags;
uint64_t curPos = 0;
+
+ bool compatibleWith(uint32_t secFlags) const {
+ if ((secFlags & negFlags) || (~secFlags & negInvFlags))
+ return false;
+ return (secFlags & flags) || (~secFlags & invFlags);
+ }
};
// This struct represents one section match pattern in SECTIONS() command.
@@ -166,7 +183,7 @@ public:
SortSectionPolicy sortInner;
};
-class InputSectionDescription : public BaseCommand {
+class InputSectionDescription : public SectionCommand {
SingleStringMatcher filePat;
// Cache of the most recent input argument and result of matchesFile().
@@ -175,10 +192,10 @@ class InputSectionDescription : public BaseCommand {
public:
InputSectionDescription(StringRef filePattern, uint64_t withFlags = 0,
uint64_t withoutFlags = 0)
- : BaseCommand(InputSectionKind), filePat(filePattern),
+ : SectionCommand(InputSectionKind), filePat(filePattern),
withFlags(withFlags), withoutFlags(withoutFlags) {}
- static bool classof(const BaseCommand *c) {
+ static bool classof(const SectionCommand *c) {
return c->kind == InputSectionKind;
}
@@ -207,12 +224,12 @@ public:
};
// Represents BYTE(), SHORT(), LONG(), or QUAD().
-struct ByteCommand : BaseCommand {
+struct ByteCommand : SectionCommand {
ByteCommand(Expr e, unsigned size, std::string commandString)
- : BaseCommand(ByteKind), commandString(commandString), expression(e),
+ : SectionCommand(ByteKind), commandString(commandString), expression(e),
size(size) {}
- static bool classof(const BaseCommand *c) { return c->kind == ByteKind; }
+ static bool classof(const SectionCommand *c) { return c->kind == ByteKind; }
// Keeps string representing the command. Used for -Map" is perhaps better.
std::string commandString;
@@ -275,10 +292,6 @@ class LinkerScript final {
std::pair<MemoryRegion *, MemoryRegion *>
findMemoryRegion(OutputSection *sec, MemoryRegion *hint);
- void switchTo(OutputSection *sec);
- uint64_t advance(uint64_t size, unsigned align);
- void output(InputSection *sec);
-
void assignOffsets(OutputSection *sec);
// Ctx captures the local AddressState and makes it accessible
@@ -324,7 +337,7 @@ public:
void processInsertCommands();
// SECTIONS command list.
- std::vector<BaseCommand *> sectionCommands;
+ std::vector<SectionCommand *> sectionCommands;
// PHDRS command list.
std::vector<PhdrsCommand> phdrsCommands;
diff --git a/lld/ELF/MapFile.cpp b/lld/ELF/MapFile.cpp
index c4690ae5aefd..06735802f7f1 100644
--- a/lld/ELF/MapFile.cpp
+++ b/lld/ELF/MapFile.cpp
@@ -139,20 +139,7 @@ static void printEhFrame(raw_ostream &os, const EhFrameSection *sec) {
}
}
-void elf::writeMapFile() {
- if (config->mapFile.empty())
- return;
-
- llvm::TimeTraceScope timeScope("Write map file");
-
- // Open a map file for writing.
- std::error_code ec;
- raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None);
- if (ec) {
- error("cannot open " + config->mapFile + ": " + ec.message());
- return;
- }
-
+static void writeMapFile(raw_fd_ostream &os) {
// Collect symbol info that we want to print out.
std::vector<Defined *> syms = getSymbols();
SymbolMapTy sectionSyms = getSectionSyms(syms);
@@ -164,30 +151,30 @@ void elf::writeMapFile() {
<< " Size Align Out In Symbol\n";
OutputSection* osec = nullptr;
- for (BaseCommand *base : script->sectionCommands) {
- if (auto *cmd = dyn_cast<SymbolAssignment>(base)) {
- if (cmd->provide && !cmd->sym)
+ for (SectionCommand *cmd : script->sectionCommands) {
+ if (auto *assign = dyn_cast<SymbolAssignment>(cmd)) {
+ if (assign->provide && !assign->sym)
continue;
- uint64_t lma = osec ? osec->getLMA() + cmd->addr - osec->getVA(0) : 0;
- writeHeader(os, cmd->addr, lma, cmd->size, 1);
- os << cmd->commandString << '\n';
+ uint64_t lma = osec ? osec->getLMA() + assign->addr - osec->getVA(0) : 0;
+ writeHeader(os, assign->addr, lma, assign->size, 1);
+ os << assign->commandString << '\n';
continue;
}
- osec = cast<OutputSection>(base);
+ osec = cast<OutputSection>(cmd);
writeHeader(os, osec->addr, osec->getLMA(), osec->size, osec->alignment);
os << osec->name << '\n';
// Dump symbols for each input section.
- for (BaseCommand *base : osec->sectionCommands) {
- if (auto *isd = dyn_cast<InputSectionDescription>(base)) {
+ for (SectionCommand *subCmd : osec->commands) {
+ if (auto *isd = dyn_cast<InputSectionDescription>(subCmd)) {
for (InputSection *isec : isd->sections) {
if (auto *ehSec = dyn_cast<EhFrameSection>(isec)) {
printEhFrame(os, ehSec);
continue;
}
- writeHeader(os, isec->getVA(0), osec->getLMA() + isec->getOffset(0),
+ writeHeader(os, isec->getVA(), osec->getLMA() + isec->outSecOff,
isec->getSize(), isec->alignment);
os << indent8 << toString(isec) << '\n';
for (Symbol *sym : sectionSyms[isec])
@@ -196,19 +183,20 @@ void elf::writeMapFile() {
continue;
}
- if (auto *cmd = dyn_cast<ByteCommand>(base)) {
- writeHeader(os, osec->addr + cmd->offset, osec->getLMA() + cmd->offset,
- cmd->size, 1);
- os << indent8 << cmd->commandString << '\n';
+ if (auto *data = dyn_cast<ByteCommand>(subCmd)) {
+ writeHeader(os, osec->addr + data->offset,
+ osec->getLMA() + data->offset, data->size, 1);
+ os << indent8 << data->commandString << '\n';
continue;
}
- if (auto *cmd = dyn_cast<SymbolAssignment>(base)) {
- if (cmd->provide && !cmd->sym)
+ if (auto *assign = dyn_cast<SymbolAssignment>(subCmd)) {
+ if (assign->provide && !assign->sym)
continue;
- writeHeader(os, cmd->addr, osec->getLMA() + cmd->addr - osec->getVA(0),
- cmd->size, 1);
- os << indent8 << cmd->commandString << '\n';
+ writeHeader(os, assign->addr,
+ osec->getLMA() + assign->addr - osec->getVA(0),
+ assign->size, 1);
+ os << indent8 << assign->commandString << '\n';
continue;
}
}
@@ -234,10 +222,6 @@ void elf::writeWhyExtract() {
}
}
-static void print(StringRef a, StringRef b) {
- lld::outs() << left_justify(a, 49) << " " << b << "\n";
-}
-
// Output a cross reference table to stdout. This is for --cref.
//
// For each global symbol, we print out a file that defines the symbol
@@ -249,10 +233,7 @@ static void print(StringRef a, StringRef b) {
//
// In this case, strlen is defined by libc.so.6 and used by other two
// files.
-void elf::writeCrossReferenceTable() {
- if (!config->cref)
- return;
-
+static void writeCref(raw_fd_ostream &os) {
// Collect symbols and files.
MapVector<Symbol *, SetVector<InputFile *>> map;
for (InputFile *file : objectFiles) {
@@ -265,8 +246,12 @@ void elf::writeCrossReferenceTable() {
}
}
- // Print out a header.
- lld::outs() << "Cross Reference Table\n\n";
+ auto print = [&](StringRef a, StringRef b) {
+ os << left_justify(a, 49) << ' ' << b << '\n';
+ };
+
+ // Print a blank line and a header. The format matches GNU ld.
+ os << "\nCross Reference Table\n\n";
print("Symbol", "File");
// Print out a table.
@@ -281,6 +266,27 @@ void elf::writeCrossReferenceTable() {
}
}
+void elf::writeMapAndCref() {
+ if (config->mapFile.empty() && !config->cref)
+ return;
+
+ llvm::TimeTraceScope timeScope("Write map file");
+
+ // Open a map file for writing.
+ std::error_code ec;
+ StringRef mapFile = config->mapFile.empty() ? "-" : config->mapFile;
+ raw_fd_ostream os(mapFile, ec, sys::fs::OF_None);
+ if (ec) {
+ error("cannot open " + mapFile + ": " + ec.message());
+ return;
+ }
+
+ if (!config->mapFile.empty())
+ writeMapFile(os);
+ if (config->cref)
+ writeCref(os);
+}
+
void elf::writeArchiveStats() {
if (config->printArchiveStats.empty())
return;
@@ -293,8 +299,8 @@ void elf::writeArchiveStats() {
return;
}
- os << "members\tfetched\tarchive\n";
+ os << "members\textracted\tarchive\n";
for (const ArchiveFile *f : archiveFiles)
- os << f->getMemberCount() << '\t' << f->getFetchedMemberCount() << '\t'
+ os << f->getMemberCount() << '\t' << f->getExtractedMemberCount() << '\t'
<< f->getName() << '\n';
}
diff --git a/lld/ELF/MapFile.h b/lld/ELF/MapFile.h
index 1b8c0168c0de..df548988c03b 100644
--- a/lld/ELF/MapFile.h
+++ b/lld/ELF/MapFile.h
@@ -11,9 +11,8 @@
namespace lld {
namespace elf {
-void writeMapFile();
+void writeMapAndCref();
void writeWhyExtract();
-void writeCrossReferenceTable();
void writeArchiveStats();
} // namespace elf
} // namespace lld
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index ce82eb8d2754..f9f9f54a80d8 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -129,7 +129,8 @@ def color_diagnostics_eq: J<"color-diagnostics=">,
HelpText<"Use colors in diagnostics (default: auto)">,
MetaVarName<"[auto,always,never]">;
-def cref: FF<"cref">, HelpText<"Output cross reference table">;
+def cref: FF<"cref">,
+ HelpText<"Output cross reference table. If -Map is specified, print to the map file">;
defm define_common: B<"define-common",
"Assign space to common symbols",
@@ -304,8 +305,8 @@ def no_undefined: F<"no-undefined">,
def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
HelpText<"Path to file to write output">;
-def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">,
- HelpText<"Specify the binary format for the output object file">;
+defm oformat: EEq<"oformat", "Specify the binary format for the output object file">,
+ MetaVarName<"[elf,binary]">;
def omagic: FF<"omagic">, MetaVarName<"<magic>">,
HelpText<"Set the text and data sections to be readable and writable, do not page align sections, link against static libraries">;
@@ -338,7 +339,7 @@ defm print_icf_sections: B<"print-icf-sections",
def print_archive_stats: J<"print-archive-stats=">,
HelpText<"Write archive usage statistics to the specified file. "
- "Print the numbers of members and fetched members for each archive">;
+ "Print the numbers of members and extracted members for each archive">;
defm print_symbol_order: Eq<"print-symbol-order",
"Print a symbol order specified by --call-graph-ordering-file into the specified file">;
@@ -454,22 +455,19 @@ def verbose: F<"verbose">, HelpText<"Verbose mode">;
def version: F<"version">, HelpText<"Display the version number and exit">;
-def power10_stubs: F<"power10-stubs">, HelpText<"Alias for --power10-stubs=auto">;
-
-def no_power10_stubs: F<"no-power10-stubs">, HelpText<"Alias for --power10-stubs=no">;
-
-def power10_stubs_eq:
- J<"power10-stubs=">, HelpText<
- "Enables Power10 instructions in all stubs without options, "
- "options override previous flags."
- "auto: Allow Power10 instructions in stubs if applicable."
- "no: No Power10 instructions in stubs.">;
+def power10_stubs_eq: JJ<"power10-stubs=">, MetaVarName<"<mode>">,
+ HelpText<"Whether to use Power10 instructions in call stubs for R_PPC64_REL24_NOTOC and TOC/NOTOC "
+ "interworking (yes (default): use; no: don't use). \"auto\" is currently the same as \"yes\"">;
+def power10_stubs: FF<"power10-stubs">, Alias<power10_stubs_eq>, AliasArgs<["yes"]>,
+ HelpText<"Alias for --power10-stubs=auto">;
+def no_power10_stubs: FF<"no-power10-stubs">, Alias<power10_stubs_eq>, AliasArgs<["no"]>,
+ HelpText<"Alias for --power10-stubs=no">;
defm version_script: Eq<"version-script", "Read a version script">;
defm warn_backrefs: BB<"warn-backrefs",
- "Warn about backward symbol references to fetch archive members",
- "Do not warn about backward symbol references to fetch archive members (default)">;
+ "Warn about backward symbol references to extract archive members",
+ "Do not warn about backward symbol references to extract archive members (default)">;
defm warn_backrefs_exclude
: EEq<"warn-backrefs-exclude",
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index cc4f0688701a..a17f713b742a 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -33,7 +33,6 @@ using namespace lld;
using namespace lld::elf;
uint8_t *Out::bufferStart;
-uint8_t Out::first;
PhdrEntry *Out::tlsPhdr;
OutputSection *Out::elfHeader;
OutputSection *Out::programHeaders;
@@ -69,7 +68,7 @@ void OutputSection::writeHeaderTo(typename ELFT::Shdr *shdr) {
}
OutputSection::OutputSection(StringRef name, uint32_t type, uint64_t flags)
- : BaseCommand(OutputSectionKind),
+ : SectionCommand(OutputSectionKind),
SectionBase(Output, name, flags, /*Entsize*/ 0, /*Alignment*/ 1, type,
/*Info*/ 0, /*Link*/ 0) {}
@@ -100,10 +99,9 @@ static bool canMergeToProgbits(unsigned type) {
void OutputSection::recordSection(InputSectionBase *isec) {
partition = isec->partition;
isec->parent = this;
- if (sectionCommands.empty() ||
- !isa<InputSectionDescription>(sectionCommands.back()))
- sectionCommands.push_back(make<InputSectionDescription>(""));
- auto *isd = cast<InputSectionDescription>(sectionCommands.back());
+ if (commands.empty() || !isa<InputSectionDescription>(commands.back()))
+ commands.push_back(make<InputSectionDescription>(""));
+ auto *isd = cast<InputSectionDescription>(commands.back());
isd->sectionBases.push_back(isec);
}
@@ -166,15 +164,15 @@ void OutputSection::commitSection(InputSection *isec) {
// to compute an output offset for each piece of each input section.
void OutputSection::finalizeInputSections() {
std::vector<MergeSyntheticSection *> mergeSections;
- for (BaseCommand *base : sectionCommands) {
- auto *cmd = dyn_cast<InputSectionDescription>(base);
- if (!cmd)
+ for (SectionCommand *cmd : commands) {
+ auto *isd = dyn_cast<InputSectionDescription>(cmd);
+ if (!isd)
continue;
- cmd->sections.reserve(cmd->sectionBases.size());
- for (InputSectionBase *s : cmd->sectionBases) {
+ isd->sections.reserve(isd->sectionBases.size());
+ for (InputSectionBase *s : isd->sectionBases) {
MergeInputSection *ms = dyn_cast<MergeInputSection>(s);
if (!ms) {
- cmd->sections.push_back(cast<InputSection>(s));
+ isd->sections.push_back(cast<InputSection>(s));
continue;
}
@@ -203,17 +201,17 @@ void OutputSection::finalizeInputSections() {
mergeSections.push_back(syn);
i = std::prev(mergeSections.end());
syn->entsize = ms->entsize;
- cmd->sections.push_back(syn);
+ isd->sections.push_back(syn);
}
(*i)->addSection(ms);
}
// sectionBases should not be used from this point onwards. Clear it to
// catch misuses.
- cmd->sectionBases.clear();
+ isd->sectionBases.clear();
// Some input sections may be removed from the list after ICF.
- for (InputSection *s : cmd->sections)
+ for (InputSection *s : isd->sections)
commitSection(s);
}
for (auto *ms : mergeSections)
@@ -237,13 +235,13 @@ uint64_t elf::getHeaderSize() {
return Out::elfHeader->size + Out::programHeaders->size;
}
-bool OutputSection::classof(const BaseCommand *c) {
+bool OutputSection::classof(const SectionCommand *c) {
return c->kind == OutputSectionKind;
}
void OutputSection::sort(llvm::function_ref<int(InputSectionBase *s)> order) {
assert(isLive());
- for (BaseCommand *b : sectionCommands)
+ for (SectionCommand *b : commands)
if (auto *isd = dyn_cast<InputSectionDescription>(b))
sortByOrder(isd->sections, order);
}
@@ -367,8 +365,8 @@ template <class ELFT> void OutputSection::writeTo(uint8_t *buf) {
// 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))
+ for (SectionCommand *cmd : commands)
+ if (auto *data = dyn_cast<ByteCommand>(cmd))
writeInt(buf + data->offset, data->expression().getValue(), data->size);
}
@@ -485,8 +483,8 @@ static bool compCtors(const InputSection *a, const InputSection *b) {
// 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]);
+ assert(commands.size() == 1);
+ auto *isd = cast<InputSectionDescription>(commands[0]);
llvm::stable_sort(isd->sections, compCtors);
}
@@ -505,8 +503,8 @@ int elf::getPriority(StringRef s) {
}
InputSection *elf::getFirstInputSection(const OutputSection *os) {
- for (BaseCommand *base : os->sectionCommands)
- if (auto *isd = dyn_cast<InputSectionDescription>(base))
+ for (SectionCommand *cmd : os->commands)
+ if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
if (!isd->sections.empty())
return isd->sections[0];
return nullptr;
@@ -514,8 +512,8 @@ InputSection *elf::getFirstInputSection(const OutputSection *os) {
std::vector<InputSection *> elf::getInputSections(const OutputSection *os) {
std::vector<InputSection *> ret;
- for (BaseCommand *base : os->sectionCommands)
- if (auto *isd = dyn_cast<InputSectionDescription>(base))
+ for (SectionCommand *cmd : os->commands)
+ if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
ret.insert(ret.end(), isd->sections.begin(), isd->sections.end());
return ret;
}
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index a0f806614387..a5b05cf28aa8 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -29,7 +29,7 @@ class InputSectionBase;
// 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 BaseCommand, public SectionBase {
+class OutputSection final : public SectionCommand, public SectionBase {
public:
OutputSection(StringRef name, uint32_t type, uint64_t flags);
@@ -37,7 +37,7 @@ public:
return s->kind() == SectionBase::Output;
}
- static bool classof(const BaseCommand *c);
+ static bool classof(const SectionCommand *c);
uint64_t getLMA() const { return ptLoad ? addr + ptLoad->lmaOffset : addr; }
template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *sHdr);
@@ -82,7 +82,7 @@ public:
Expr alignExpr;
Expr lmaExpr;
Expr subalignExpr;
- std::vector<BaseCommand *> sectionCommands;
+ std::vector<SectionCommand *> commands;
std::vector<StringRef> phdrs;
llvm::Optional<std::array<uint8_t, 4>> filler;
ConstraintKind constraint = ConstraintKind::NoConstraint;
@@ -128,7 +128,6 @@ std::vector<InputSection *> getInputSections(const OutputSection *os);
// until Writer is initialized.
struct Out {
static uint8_t *bufferStart;
- static uint8_t first;
static PhdrEntry *tlsPhdr;
static OutputSection *elfHeader;
static OutputSection *programHeaders;
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 9c22ce7d6013..5136ba2151a3 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -66,10 +66,10 @@ using namespace lld;
using namespace lld::elf;
static Optional<std::string> getLinkerScriptLocation(const Symbol &sym) {
- for (BaseCommand *base : script->sectionCommands)
- if (auto *cmd = dyn_cast<SymbolAssignment>(base))
- if (cmd->sym == &sym)
- return cmd->location;
+ for (SectionCommand *cmd : script->sectionCommands)
+ if (auto *assign = dyn_cast<SymbolAssignment>(cmd))
+ if (assign->sym == &sym)
+ return assign->location;
return None;
}
@@ -366,10 +366,10 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &ss) {
// At this point, sectionBases has been migrated to sections. Append sec to
// sections.
- if (osec->sectionCommands.empty() ||
- !isa<InputSectionDescription>(osec->sectionCommands.back()))
- osec->sectionCommands.push_back(make<InputSectionDescription>(""));
- auto *isd = cast<InputSectionDescription>(osec->sectionCommands.back());
+ if (osec->commands.empty() ||
+ !isa<InputSectionDescription>(osec->commands.back()))
+ osec->commands.push_back(make<InputSectionDescription>(""));
+ auto *isd = cast<InputSectionDescription>(osec->commands.back());
isd->sections.push_back(sec);
osec->commitSection(sec);
@@ -1358,32 +1358,6 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
}
}
- // Relax relocations.
- //
- // 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 executable, all dynamic symbols that can
- // be resolved within the executable will actually be resolved that way at
- // runtime, because the main executable is always at the beginning of a search
- // list. We can leverage that fact.
- if (!sym.isPreemptible && (!sym.isGnuIFunc() || config->zIfuncNoplt)) {
- if (expr != R_GOT_PC) {
- // The 0x8000 bit of r_addend of R_PPC_PLTREL24 is used to choose call
- // stub type. It should be ignored if optimized to R_PC.
- if (config->emachine == EM_PPC && expr == R_PPC32_PLTREL)
- addend &= ~0x8000;
- // R_HEX_GD_PLT_B22_PCREL (call a@GDPLT) is transformed into
- // call __tls_get_addr even if the symbol is non-preemptible.
- if (!(config->emachine == EM_HEXAGON &&
- (type == R_HEX_GD_PLT_B22_PCREL ||
- type == R_HEX_GD_PLT_B22_PCREL_X ||
- type == R_HEX_GD_PLT_B32_PCREL_X)))
- expr = fromPlt(expr);
- } else if (!isAbsoluteValue(sym)) {
- expr = target->adjustGotPcExpr(type, addend, relocatedAddr);
- }
- }
-
// If the relocation does not emit a GOT or GOTPLT entry but its computation
// uses their addresses, we need GOT or GOTPLT to be created.
//
@@ -1411,6 +1385,32 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
return;
}
+ // Relax relocations.
+ //
+ // 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 executable, all dynamic symbols that can
+ // be resolved within the executable will actually be resolved that way at
+ // runtime, because the main executable is always at the beginning of a search
+ // list. We can leverage that fact.
+ if (!sym.isPreemptible && (!sym.isGnuIFunc() || config->zIfuncNoplt)) {
+ if (expr != R_GOT_PC) {
+ // The 0x8000 bit of r_addend of R_PPC_PLTREL24 is used to choose call
+ // stub type. It should be ignored if optimized to R_PC.
+ if (config->emachine == EM_PPC && expr == R_PPC32_PLTREL)
+ addend &= ~0x8000;
+ // R_HEX_GD_PLT_B22_PCREL (call a@GDPLT) is transformed into
+ // call __tls_get_addr even if the symbol is non-preemptible.
+ if (!(config->emachine == EM_HEXAGON &&
+ (type == R_HEX_GD_PLT_B22_PCREL ||
+ type == R_HEX_GD_PLT_B22_PCREL_X ||
+ type == R_HEX_GD_PLT_B32_PCREL_X)))
+ expr = fromPlt(expr);
+ } else if (!isAbsoluteValue(sym)) {
+ expr = target->adjustGotPcExpr(type, addend, relocatedAddr);
+ }
+ }
+
// We were asked not to generate PLT entries for ifuncs. Instead, pass the
// direct relocation on through.
if (sym.isGnuIFunc() && config->zIfuncNoplt) {
@@ -1640,7 +1640,7 @@ static void forEachInputSectionDescription(
for (OutputSection *os : outputSections) {
if (!(os->flags & SHF_ALLOC) || !(os->flags & SHF_EXECINSTR))
continue;
- for (BaseCommand *bc : os->sectionCommands)
+ for (SectionCommand *bc : os->commands)
if (auto *isd = dyn_cast<InputSectionDescription>(bc))
fn(os, isd);
}
@@ -1817,7 +1817,7 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *isec) {
// Find InputSectionRange within Target Output Section (TOS) that the
// InputSection (IS) that we need to precede is in.
OutputSection *tos = isec->getParent();
- for (BaseCommand *bc : tos->sectionCommands) {
+ for (SectionCommand *bc : tos->commands) {
auto *isd = dyn_cast<InputSectionDescription>(bc);
if (!isd || isd->sections.empty())
continue;
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index ad3b3e61ad59..d3b0296acab0 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -93,7 +93,7 @@ private:
void readSectionAddressType(OutputSection *cmd);
OutputSection *readOverlaySectionDescription();
OutputSection *readOutputSectionDescription(StringRef outSec);
- std::vector<BaseCommand *> readOverlay();
+ std::vector<SectionCommand *> readOverlay();
std::vector<StringRef> readOutputSectionPhdrs();
std::pair<uint64_t, uint64_t> readInputSectionFlags();
InputSectionDescription *readInputSectionDescription(StringRef tok);
@@ -113,7 +113,8 @@ private:
Expr getPageSize();
Expr readMemoryAssignment(StringRef, StringRef, StringRef);
- std::pair<uint32_t, uint32_t> readMemoryAttributes();
+ void readMemoryAttributes(uint32_t &flags, uint32_t &invFlags,
+ uint32_t &negFlags, uint32_t &negInvFlags);
Expr combine(StringRef op, Expr l, Expr r);
Expr readExpr();
@@ -518,7 +519,7 @@ void ScriptParser::readSearchDir() {
// sections that use the same virtual memory range and normally would trigger
// linker's sections sanity check failures.
// https://sourceware.org/binutils/docs/ld/Overlay-Description.html#Overlay-Description
-std::vector<BaseCommand *> ScriptParser::readOverlay() {
+std::vector<SectionCommand *> ScriptParser::readOverlay() {
// VA and LMA expressions are optional, though for simplicity of
// implementation we assume they are not. That is what OVERLAY was designed
// for first of all: to allow sections with overlapping VAs at different LMAs.
@@ -528,7 +529,7 @@ std::vector<BaseCommand *> ScriptParser::readOverlay() {
Expr lmaExpr = readParenExpr();
expect("{");
- std::vector<BaseCommand *> v;
+ std::vector<SectionCommand *> v;
OutputSection *prev = nullptr;
while (!errorCount() && !consume("}")) {
// VA is the same for all sections. The LMAs are consecutive in memory
@@ -549,7 +550,7 @@ std::vector<BaseCommand *> ScriptParser::readOverlay() {
// Here we want to create the Dot assignment command to achieve that.
Expr moveDot = [=] {
uint64_t max = 0;
- for (BaseCommand *cmd : v)
+ for (SectionCommand *cmd : v)
max = std::max(max, cast<OutputSection>(cmd)->size);
return addrExpr().getValue() + max;
};
@@ -565,11 +566,11 @@ void ScriptParser::readOverwriteSections() {
void ScriptParser::readSections() {
expect("{");
- std::vector<BaseCommand *> v;
+ std::vector<SectionCommand *> v;
while (!errorCount() && !consume("}")) {
StringRef tok = next();
if (tok == "OVERLAY") {
- for (BaseCommand *cmd : readOverlay())
+ for (SectionCommand *cmd : readOverlay())
v.push_back(cmd);
continue;
} else if (tok == "INCLUDE") {
@@ -577,7 +578,7 @@ void ScriptParser::readSections() {
continue;
}
- if (BaseCommand *cmd = readAssignment(tok))
+ if (SectionCommand *cmd = readAssignment(tok))
v.push_back(cmd);
else
v.push_back(readOutputSectionDescription(tok));
@@ -597,7 +598,7 @@ void ScriptParser::readSections() {
setError("expected AFTER/BEFORE, but got '" + next() + "'");
StringRef where = next();
std::vector<StringRef> names;
- for (BaseCommand *cmd : v)
+ for (SectionCommand *cmd : v)
if (auto *os = dyn_cast<OutputSection>(cmd))
names.push_back(os->name);
if (!names.empty())
@@ -848,7 +849,7 @@ OutputSection *ScriptParser::readOverlaySectionDescription() {
uint64_t withoutFlags = 0;
if (consume("INPUT_SECTION_FLAGS"))
std::tie(withFlags, withoutFlags) = readInputSectionFlags();
- cmd->sectionCommands.push_back(
+ cmd->commands.push_back(
readInputSectionRules(next(), withFlags, withoutFlags));
}
return cmd;
@@ -884,9 +885,9 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) {
if (tok == ";") {
// Empty commands are allowed. Do nothing here.
} else if (SymbolAssignment *assign = readAssignment(tok)) {
- cmd->sectionCommands.push_back(assign);
+ cmd->commands.push_back(assign);
} else if (ByteCommand *data = readByteCommand(tok)) {
- cmd->sectionCommands.push_back(data);
+ cmd->commands.push_back(data);
} else if (tok == "CONSTRUCTORS") {
// CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors
// by name. This is for very old file formats such as ECOFF/XCOFF.
@@ -903,7 +904,7 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) {
} else if (tok == "INCLUDE") {
readInclude();
} else if (peek() == "(") {
- cmd->sectionCommands.push_back(readInputSectionDescription(tok));
+ cmd->commands.push_back(readInputSectionDescription(tok));
} else {
// We have a file name and no input sections description. It is not a
// commonly used syntax, but still acceptable. In that case, all sections
@@ -913,7 +914,7 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) {
// case above.
auto *isd = make<InputSectionDescription>(tok);
isd->sectionPatterns.push_back({{}, StringMatcher("*")});
- cmd->sectionCommands.push_back(isd);
+ cmd->commands.push_back(isd);
}
}
@@ -1614,9 +1615,11 @@ void ScriptParser::readMemory() {
}
uint32_t flags = 0;
+ uint32_t invFlags = 0;
uint32_t negFlags = 0;
+ uint32_t negInvFlags = 0;
if (consume("(")) {
- std::tie(flags, negFlags) = readMemoryAttributes();
+ readMemoryAttributes(flags, invFlags, negFlags, negInvFlags);
expect(")");
}
expect(":");
@@ -1626,7 +1629,8 @@ void ScriptParser::readMemory() {
Expr length = readMemoryAssignment("LENGTH", "len", "l");
// Add the memory region to the region map.
- MemoryRegion *mr = make<MemoryRegion>(tok, origin, length, flags, negFlags);
+ MemoryRegion *mr = make<MemoryRegion>(tok, origin, length, flags, invFlags,
+ negFlags, negInvFlags);
if (!script->memoryRegions.insert({tok, mr}).second)
setError("region '" + tok + "' already defined");
}
@@ -1635,30 +1639,34 @@ void ScriptParser::readMemory() {
// This function parses the attributes used to match against section
// flags when placing output sections in a memory region. These flags
// are only used when an explicit memory region name is not used.
-std::pair<uint32_t, uint32_t> ScriptParser::readMemoryAttributes() {
- uint32_t flags = 0;
- uint32_t negFlags = 0;
+void ScriptParser::readMemoryAttributes(uint32_t &flags, uint32_t &invFlags,
+ uint32_t &negFlags,
+ uint32_t &negInvFlags) {
bool invert = false;
for (char c : next().lower()) {
- uint32_t flag = 0;
- if (c == '!')
+ if (c == '!') {
invert = !invert;
- else if (c == 'w')
- flag = SHF_WRITE;
+ std::swap(flags, negFlags);
+ std::swap(invFlags, negInvFlags);
+ continue;
+ }
+ if (c == 'w')
+ flags |= SHF_WRITE;
else if (c == 'x')
- flag = SHF_EXECINSTR;
+ flags |= SHF_EXECINSTR;
else if (c == 'a')
- flag = SHF_ALLOC;
- else if (c != 'r')
+ flags |= SHF_ALLOC;
+ else if (c == 'r')
+ invFlags |= SHF_WRITE;
+ else
setError("invalid memory region attribute");
+ }
- if (invert)
- negFlags |= flag;
- else
- flags |= flag;
+ if (invert) {
+ std::swap(flags, negFlags);
+ std::swap(invFlags, negInvFlags);
}
- return {flags, negFlags};
}
void elf::readLinkerScript(MemoryBufferRef mb) {
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index c309957ee5ba..e615fb70a40f 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -113,7 +113,7 @@ Symbol *SymbolTable::find(StringRef name) {
// A version script/dynamic list is only meaningful for a Defined symbol.
// A CommonSymbol will be converted to a Defined in replaceCommonSymbols().
-// A lazy symbol may be made Defined if an LTO libcall fetches it.
+// A lazy symbol may be made Defined if an LTO libcall extracts it.
static bool canBeVersioned(const Symbol &sym) {
return sym.isDefined() || sym.isCommon() || sym.isLazy();
}
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 5f95a1b3c7ac..8c410b4d5bfb 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -256,18 +256,11 @@ void Symbol::parseSymbolVersion() {
verstr);
}
-void Symbol::fetch() const {
- if (auto *sym = dyn_cast<LazyArchive>(this)) {
- cast<ArchiveFile>(sym->file)->fetch(sym->sym);
- return;
- }
-
- if (auto *sym = dyn_cast<LazyObject>(this)) {
- dyn_cast<LazyObjFile>(sym->file)->fetch();
- return;
- }
-
- llvm_unreachable("Symbol::fetch() is called on a non-lazy symbol");
+void Symbol::extract() const {
+ if (auto *sym = dyn_cast<LazyArchive>(this))
+ cast<ArchiveFile>(sym->file)->extract(sym->sym);
+ else
+ cast<LazyObjFile>(this->file)->extract();
}
MemoryBufferRef LazyArchive::getMemberBuffer() {
@@ -478,8 +471,8 @@ void Symbol::resolveUndefined(const Undefined &other) {
printTraceSymbol(&other);
if (isLazy()) {
- // An undefined weak will not fetch archive members. See comment on Lazy in
- // Symbols.h for the details.
+ // An undefined weak will not extract archive members. See comment on Lazy
+ // in Symbols.h for the details.
if (other.binding == STB_WEAK) {
binding = STB_WEAK;
type = other.type;
@@ -489,9 +482,9 @@ void Symbol::resolveUndefined(const Undefined &other) {
// Do extra check for --warn-backrefs.
//
// --warn-backrefs is an option to prevent an undefined reference from
- // fetching an archive member written earlier in the command line. It can be
- // used to keep compatibility with GNU linkers to some degree.
- // I'll explain the feature and why you may find it useful in this comment.
+ // extracting an archive member written earlier in the command line. It can
+ // be used to keep compatibility with GNU linkers to some degree. I'll
+ // explain the feature and why you may find it useful in this comment.
//
// lld's symbol resolution semantics is more relaxed than traditional Unix
// linkers. For example,
@@ -538,7 +531,7 @@ void Symbol::resolveUndefined(const Undefined &other) {
// group assignment rule simulates the traditional linker's semantics.
bool backref = config->warnBackrefs && other.file &&
file->groupId < other.file->groupId;
- fetch();
+ extract();
if (!config->whyExtract.empty())
recordWhyExtract(other.file, *file, *this);
@@ -712,23 +705,23 @@ template <class LazyT>
static void replaceCommon(Symbol &oldSym, const LazyT &newSym) {
backwardReferences.erase(&oldSym);
oldSym.replace(newSym);
- newSym.fetch();
+ newSym.extract();
}
template <class LazyT> void Symbol::resolveLazy(const LazyT &other) {
// For common objects, we want to look for global or weak definitions that
- // should be fetched as the canonical definition instead.
+ // should be extracted as the canonical definition instead.
if (isCommon() && elf::config->fortranCommon) {
if (auto *laSym = dyn_cast<LazyArchive>(&other)) {
ArchiveFile *archive = cast<ArchiveFile>(laSym->file);
const Archive::Symbol &archiveSym = laSym->sym;
- if (archive->shouldFetchForCommon(archiveSym)) {
+ if (archive->shouldExtractForCommon(archiveSym)) {
replaceCommon(*this, other);
return;
}
} else if (auto *loSym = dyn_cast<LazyObject>(&other)) {
LazyObjFile *obj = cast<LazyObjFile>(loSym->file);
- if (obj->shouldFetchForCommon(loSym->getName())) {
+ if (obj->shouldExtractForCommon(loSym->getName())) {
replaceCommon(*this, other);
return;
}
@@ -742,7 +735,7 @@ template <class LazyT> void Symbol::resolveLazy(const LazyT &other) {
return;
}
- // An undefined weak will not fetch archive members. See comment on Lazy in
+ // An undefined weak will not extract archive members. See comment on Lazy in
// Symbols.h for the details.
if (isWeak()) {
uint8_t ty = type;
@@ -753,7 +746,7 @@ template <class LazyT> void Symbol::resolveLazy(const LazyT &other) {
}
const InputFile *oldFile = file;
- other.fetch();
+ other.extract();
if (!config->whyExtract.empty())
recordWhyExtract(oldFile, *file, *this);
}
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 816d61563021..cc48ef0ab3b7 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -93,7 +93,7 @@ public:
// Symbol binding. This is not overwritten by replace() 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
+ // - An undefined weak will not extract archive members, but we have to
// remember it is weak.
uint8_t binding;
@@ -216,10 +216,10 @@ public:
void mergeProperties(const Symbol &other);
void resolve(const Symbol &other);
- // If this is a lazy symbol, fetch an input file and add the symbol
+ // If this is a lazy symbol, extract an input file and add the symbol
// in the file to the symbol table. Calling this function on
// non-lazy object causes a runtime error.
- void fetch() const;
+ void extract() const;
static bool isExportDynamic(Kind k, uint8_t visibility) {
if (k == SharedKind)
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index f1594eb8df86..4078f7e01674 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -900,7 +900,7 @@ void MipsGotSection::build() {
got.pagesMap) {
const OutputSection *os = p.first;
uint64_t secSize = 0;
- for (BaseCommand *cmd : os->sectionCommands) {
+ for (SectionCommand *cmd : os->commands) {
if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
for (InputSection *isec : isd->sections) {
uint64_t off = alignTo(secSize, isec->alignment);
@@ -1258,43 +1258,6 @@ DynamicSection<ELFT>::DynamicSection()
this->flags = SHF_ALLOC;
}
-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->getVA(0); }});
-}
-
-template <class ELFT>
-void DynamicSection<ELFT>::addInSecRelative(int32_t tag, InputSection *sec) {
- size_t tagOffset = entries.size() * entsize;
- entries.push_back(
- {tag, [=] { return sec->getVA(0) - (getVA() + tagOffset); }});
-}
-
-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(); }});
-}
-
// The output section .rela.dyn may include these synthetic sections:
//
// - part.relaDyn
@@ -1303,15 +1266,13 @@ void DynamicSection<ELFT>::addSym(int32_t tag, Symbol *sym) {
// .rela.dyn
//
// DT_RELASZ is the total size of the included sections.
-static std::function<uint64_t()> addRelaSz(RelocationBaseSection *relaDyn) {
- return [=]() {
- size_t size = relaDyn->getSize();
- if (in.relaIplt->getParent() == relaDyn->getParent())
- size += in.relaIplt->getSize();
- if (in.relaPlt->getParent() == relaDyn->getParent())
- size += in.relaPlt->getSize();
- return size;
- };
+static uint64_t addRelaSz(RelocationBaseSection *relaDyn) {
+ size_t size = relaDyn->getSize();
+ if (in.relaIplt->getParent() == relaDyn->getParent())
+ size += in.relaIplt->getSize();
+ if (in.relaPlt->getParent() == relaDyn->getParent())
+ size += in.relaPlt->getSize();
+ return size;
}
// A Linker script may assign the RELA relocation sections to the same
@@ -1327,9 +1288,19 @@ static uint64_t addPltRelSz() {
}
// Add remaining entries to complete .dynamic contents.
-template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
+template <class ELFT>
+std::vector<std::pair<int32_t, uint64_t>>
+DynamicSection<ELFT>::computeContents() {
elf::Partition &part = getPartition();
bool isMain = part.name.empty();
+ std::vector<std::pair<int32_t, uint64_t>> entries;
+
+ auto addInt = [&](int32_t tag, uint64_t val) {
+ entries.emplace_back(tag, val);
+ };
+ auto addInSec = [&](int32_t tag, const InputSection *sec) {
+ entries.emplace_back(tag, sec->getVA());
+ };
for (StringRef s : config->filterList)
addInt(DT_FILTER, part.dynStrTab->addString(s));
@@ -1382,7 +1353,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
}
if (!config->zText)
dtFlags |= DF_TEXTREL;
- if (config->hasStaticTlsModel)
+ if (config->hasTlsIe && config->shared)
dtFlags |= DF_STATIC_TLS;
if (dtFlags)
@@ -1401,14 +1372,11 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
if (!config->shared && !config->relocatable && !config->zRodynamic)
addInt(DT_DEBUG, 0);
- if (OutputSection *sec = part.dynStrTab->getParent())
- this->link = sec->sectionIndex;
-
if (part.relaDyn->isNeeded() ||
(in.relaIplt->isNeeded() &&
part.relaDyn->getParent() == in.relaIplt->getParent())) {
addInSec(part.relaDyn->dynamicTag, part.relaDyn);
- entries.push_back({part.relaDyn->sizeDynamicTag, addRelaSz(part.relaDyn)});
+ entries.emplace_back(part.relaDyn->sizeDynamicTag, addRelaSz(part.relaDyn));
bool isRela = config->isRela;
addInt(isRela ? DT_RELAENT : DT_RELENT,
@@ -1426,8 +1394,8 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
if (part.relrDyn && !part.relrDyn->relocs.empty()) {
addInSec(config->useAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR,
part.relrDyn);
- addSize(config->useAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
- part.relrDyn->getParent());
+ addInt(config->useAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
+ part.relrDyn->getParent()->size);
addInt(config->useAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
sizeof(Elf_Relr));
}
@@ -1439,7 +1407,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
// .rel[a].plt section.
if (isMain && (in.relaPlt->isNeeded() || in.relaIplt->isNeeded())) {
addInSec(DT_JMPREL, in.relaPlt);
- entries.push_back({DT_PLTRELSZ, addPltRelSz});
+ entries.emplace_back(DT_PLTRELSZ, addPltRelSz());
switch (config->emachine) {
case EM_MIPS:
addInSec(DT_MIPS_PLTGOT, in.gotPlt);
@@ -1481,24 +1449,24 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
if (isMain) {
if (Out::preinitArray) {
- addOutSec(DT_PREINIT_ARRAY, Out::preinitArray);
- addSize(DT_PREINIT_ARRAYSZ, Out::preinitArray);
+ addInt(DT_PREINIT_ARRAY, Out::preinitArray->addr);
+ addInt(DT_PREINIT_ARRAYSZ, Out::preinitArray->size);
}
if (Out::initArray) {
- addOutSec(DT_INIT_ARRAY, Out::initArray);
- addSize(DT_INIT_ARRAYSZ, Out::initArray);
+ addInt(DT_INIT_ARRAY, Out::initArray->addr);
+ addInt(DT_INIT_ARRAYSZ, Out::initArray->size);
}
if (Out::finiArray) {
- addOutSec(DT_FINI_ARRAY, Out::finiArray);
- addSize(DT_FINI_ARRAYSZ, Out::finiArray);
+ addInt(DT_FINI_ARRAY, Out::finiArray->addr);
+ addInt(DT_FINI_ARRAYSZ, Out::finiArray->size);
}
if (Symbol *b = symtab->find(config->init))
if (b->isDefined())
- addSym(DT_INIT, b);
+ addInt(DT_INIT, b->getVA());
if (Symbol *b = symtab->find(config->fini))
if (b->isDefined())
- addSym(DT_FINI, b);
+ addInt(DT_FINI, b->getVA());
}
if (part.verSym && part.verSym->isNeeded())
@@ -1521,8 +1489,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
addInt(DT_MIPS_FLAGS, RHF_NOTPOT);
addInt(DT_MIPS_BASE_ADDRESS, target->getImageBase());
addInt(DT_MIPS_SYMTABNO, part.dynSymTab->getNumSymbols());
-
- add(DT_MIPS_LOCAL_GOTNO, [] { return in.mipsGot->getLocalEntriesNum(); });
+ addInt(DT_MIPS_LOCAL_GOTNO, in.mipsGot->getLocalEntriesNum());
if (const Symbol *b = in.mipsGot->getFirstGlobalEntry())
addInt(DT_MIPS_GOTSYM, b->dynsymIndex);
@@ -1534,37 +1501,39 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
addInSec(DT_MIPS_RLD_MAP, in.mipsRldMap);
// Store the offset to the .rld_map section
// relative to the address of the tag.
- addInSecRelative(DT_MIPS_RLD_MAP_REL, in.mipsRldMap);
+ addInt(DT_MIPS_RLD_MAP_REL,
+ in.mipsRldMap->getVA() - (getVA() + entries.size() * entsize));
}
}
// DT_PPC_GOT indicates to glibc Secure PLT is used. If DT_PPC_GOT is absent,
// glibc assumes the old-style BSS PLT layout which we don't support.
if (config->emachine == EM_PPC)
- add(DT_PPC_GOT, [] { return in.got->getVA(); });
+ addInSec(DT_PPC_GOT, in.got);
// Glink dynamic tag is required by the V2 abi if the plt section isn't empty.
if (config->emachine == EM_PPC64 && in.plt->isNeeded()) {
// The Glink tag points to 32 bytes before the first lazy symbol resolution
// stub, which starts directly after the header.
- entries.push_back({DT_PPC64_GLINK, [=] {
- unsigned offset = target->pltHeaderSize - 32;
- return in.plt->getVA(0) + offset;
- }});
+ addInt(DT_PPC64_GLINK, in.plt->getVA() + target->pltHeaderSize - 32);
}
addInt(DT_NULL, 0);
+ return entries;
+}
- getParent()->link = this->link;
- this->size = entries.size() * this->entsize;
+template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
+ if (OutputSection *sec = getPartition().dynStrTab->getParent())
+ getParent()->link = sec->sectionIndex;
+ this->size = computeContents().size() * this->entsize;
}
template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *buf) {
auto *p = reinterpret_cast<Elf_Dyn *>(buf);
- for (std::pair<int32_t, std::function<uint64_t()>> &kv : entries) {
+ for (std::pair<int32_t, uint64_t> kv : computeContents()) {
p->d_tag = kv.first;
- p->d_un.d_val = kv.second();
+ p->d_un.d_val = kv.second;
++p;
}
}
@@ -2331,8 +2300,8 @@ bool SymtabShndxSection::isNeeded() const {
// late, and we do not know them here. For simplicity, we just always create
// a .symtab_shndx section when the amount of output sections is huge.
size_t size = 0;
- for (BaseCommand *base : script->sectionCommands)
- if (isa<OutputSection>(base))
+ for (SectionCommand *cmd : script->sectionCommands)
+ if (isa<OutputSection>(cmd))
++size;
return size >= SHN_LORESERVE;
}
@@ -2411,21 +2380,8 @@ void GnuHashTableSection::writeTo(uint8_t *buf) {
write32(buf + 12, Shift2);
buf += 16;
- // Write a bloom filter and a hash table.
- writeBloomFilter(buf);
- buf += config->wordsize * maskWords;
- writeHashTable(buf);
-}
-
-// This function writes a 2-bit bloom filter. This bloom filter alone
-// usually filters out 80% or more of all symbol lookups [1].
-// The dynamic linker uses the hash table only when a symbol is not
-// filtered out by a bloom filter.
-//
-// [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2),
-// p.9, https://www.akkadia.org/drepper/dsohowto.pdf
-void GnuHashTableSection::writeBloomFilter(uint8_t *buf) {
- unsigned c = config->is64 ? 64 : 32;
+ // Write the 2-bit bloom filter.
+ const unsigned c = config->is64 ? 64 : 32;
for (const Entry &sym : symbols) {
// When C = 64, we choose a word with bits [6:...] and set 1 to two bits in
// the word using bits [0:5] and [26:31].
@@ -2435,9 +2391,9 @@ void GnuHashTableSection::writeBloomFilter(uint8_t *buf) {
val |= uint64_t(1) << ((sym.hash >> Shift2) % c);
writeUint(buf + i * config->wordsize, val);
}
-}
+ buf += config->wordsize * maskWords;
-void GnuHashTableSection::writeHashTable(uint8_t *buf) {
+ // Write the hash table.
uint32_t *buckets = reinterpret_cast<uint32_t *>(buf);
uint32_t oldBucket = -1;
uint32_t *values = buckets + nBuckets;
@@ -3160,7 +3116,7 @@ size_t VersionTableSection::getSize() const {
void VersionTableSection::writeTo(uint8_t *buf) {
buf += 2;
for (const SymbolTableEntry &s : getPartition().dynSymTab->getSymbols()) {
- // For an unfetched lazy symbol (undefined weak), it must have been
+ // For an unextracted lazy symbol (undefined weak), it must have been
// converted to Undefined and have VER_NDX_GLOBAL version here.
assert(!s.sym->isLazy());
write16(buf, s.sym->versionId);
@@ -3648,8 +3604,8 @@ PPC32Got2Section::PPC32Got2Section()
bool PPC32Got2Section::isNeeded() const {
// See the comment below. This is not needed if there is no other
// InputSection.
- for (BaseCommand *base : getParent()->sectionCommands)
- if (auto *isd = dyn_cast<InputSectionDescription>(base))
+ for (SectionCommand *cmd : getParent()->commands)
+ if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
for (InputSection *isec : isd->sections)
if (isec != this)
return true;
@@ -3662,8 +3618,8 @@ void PPC32Got2Section::finalizeContents() {
// PPC32PltCallStub::writeTo(). The purpose of this empty synthetic section is
// to collect input sections named ".got2".
uint32_t offset = 0;
- for (BaseCommand *base : getParent()->sectionCommands)
- if (auto *isd = dyn_cast<InputSectionDescription>(base)) {
+ for (SectionCommand *cmd : getParent()->commands)
+ if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) {
for (InputSection *isec : isd->sections) {
if (isec == this)
continue;
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index bc24922598fe..3d2e73071d09 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -493,9 +493,6 @@ private:
template <class ELFT> class DynamicSection final : public SyntheticSection {
LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
- // finalizeContents() fills this vector with the section contents.
- std::vector<std::pair<int32_t, std::function<uint64_t()>>> entries;
-
public:
DynamicSection();
void finalizeContents() override;
@@ -503,14 +500,7 @@ public:
size_t getSize() const override { return size; }
private:
- 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 addInSecRelative(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);
-
+ std::vector<std::pair<int32_t, uint64_t>> computeContents();
uint64_t size = 0;
};
@@ -685,9 +675,6 @@ private:
// See the comment in writeBloomFilter.
enum { Shift2 = 26 };
- void writeBloomFilter(uint8_t *buf);
- void writeHashTable(uint8_t *buf);
-
struct Entry {
Symbol *sym;
size_t strTabOffset;
diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp
index dbc476ffeeb7..ffbc8d94a800 100644
--- a/lld/ELF/Thunks.cpp
+++ b/lld/ELF/Thunks.cpp
@@ -399,24 +399,6 @@ public:
}
};
-// A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
-// alignment. This gives a possible 26 bits of 'reach'. If the caller and
-// callee do not use toc and the call offset is larger than 26 bits,
-// we need to emit a pc-rel based long-branch thunk. The target address of
-// the callee is computed with a PC-relative offset.
-class PPC64PCRelLongBranchThunk final : public Thunk {
-public:
- PPC64PCRelLongBranchThunk(Symbol &dest, int64_t addend)
- : Thunk(dest, addend) {
- alignment = 16;
- }
- uint32_t size() override { return 32; }
- void writeTo(uint8_t *buf) override;
- void addSymbols(ThunkSection &isec) override;
- bool isCompatibleWith(const InputSection &isec,
- const Relocation &rel) const override;
-};
-
} // end anonymous namespace
Defined *Thunk::addSymbol(StringRef name, uint8_t type, uint64_t value,
@@ -932,7 +914,7 @@ void PPC64R2SaveStub::writeTo(uint8_t *buf) {
write32(buf + 4, 0x48000000 | (offset & 0x03fffffc)); // b <offset>
} else if (isInt<34>(offset)) {
int nextInstOffset;
- if (!config->Power10Stub) {
+ if (!config->power10Stubs) {
uint64_t tocOffset = destination.getVA() - getPPC64TocBase();
if (tocOffset >> 16 > 0) {
const uint64_t addi = ADDI_R12_TO_R12_NO_DISP | (tocOffset & 0xffff);
@@ -980,7 +962,7 @@ void PPC64R12SetupStub::writeTo(uint8_t *buf) {
reportRangeError(buf, offset, 34, destination, "R12 setup stub offset");
int nextInstOffset;
- if (!config->Power10Stub) {
+ if (!config->power10Stubs) {
uint32_t off = destination.getVA(addend) - getThunkTargetSym()->getVA() - 8;
write32(buf + 0, 0x7c0802a6); // mflr r12
write32(buf + 4, 0x429f0005); // bcl 20,31,.+4
@@ -1013,7 +995,7 @@ void PPC64PCRelPLTStub::writeTo(uint8_t *buf) {
int nextInstOffset = 0;
int64_t offset = destination.getGotPltVA() - getThunkTargetSym()->getVA();
- if (config->Power10Stub) {
+ if (config->power10Stubs) {
if (!isInt<34>(offset))
reportRangeError(buf, offset, 34, destination,
"PC-relative PLT stub offset");
@@ -1061,42 +1043,6 @@ bool PPC64LongBranchThunk::isCompatibleWith(const InputSection &isec,
return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
}
-void PPC64PCRelLongBranchThunk::writeTo(uint8_t *buf) {
- int64_t offset = destination.getVA() - getThunkTargetSym()->getVA();
- if (!isInt<34>(offset))
- reportRangeError(buf, offset, 34, destination,
- "PC-relative long branch stub offset");
-
- int nextInstOffset;
- if (!config->Power10Stub) {
- uint32_t off = destination.getVA(addend) - getThunkTargetSym()->getVA() - 8;
- write32(buf + 0, 0x7c0802a6); // mflr r12
- write32(buf + 4, 0x429f0005); // bcl 20,31,.+4
- write32(buf + 8, 0x7d6802a6); // mflr r11
- write32(buf + 12, 0x7d8803a6); // mtlr r12
- write32(buf + 16, 0x3d8b0000 | computeHiBits(off)); // addis r12,r11,off@ha
- write32(buf + 20, 0x398c0000 | (off & 0xffff)); // addi r12,r12,off@l
- nextInstOffset = 24;
- } else {
- uint64_t paddi = PADDI_R12_NO_DISP | (((offset >> 16) & 0x3ffff) << 32) |
- (offset & 0xffff);
- writePrefixedInstruction(buf + 0, paddi); // paddi r12, 0, func@pcrel, 1
- nextInstOffset = 8;
- }
- write32(buf + nextInstOffset, MTCTR_R12); // mtctr r12
- write32(buf + nextInstOffset + 4, BCTR); // bctr
-}
-
-void PPC64PCRelLongBranchThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver.save("__long_branch_pcrel_" + destination.getName()),
- STT_FUNC, 0, isec);
-}
-
-bool PPC64PCRelLongBranchThunk::isCompatibleWith(const InputSection &isec,
- const Relocation &rel) const {
- return rel.type == R_PPC64_REL24_NOTOC;
-}
-
Thunk::Thunk(Symbol &d, int64_t a) : destination(d), addend(a), offset(0) {}
Thunk::~Thunk() = default;
@@ -1223,9 +1169,7 @@ static Thunk *addThunkPPC64(RelType type, Symbol &s, int64_t a) {
return make<PPC64R2SaveStub>(s, a);
if (type == R_PPC64_REL24_NOTOC)
- return (s.stOther >> 5) > 1
- ? (Thunk *)make<PPC64R12SetupStub>(s)
- : (Thunk *)make<PPC64PCRelLongBranchThunk>(s, a);
+ return make<PPC64R12SetupStub>(s);
if (config->picThunk)
return make<PPC64PILongBranchThunk>(s, a);
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 6d97852aec43..07c5e2303374 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -91,67 +91,6 @@ private:
};
} // anonymous namespace
-static bool isSectionPrefix(StringRef prefix, StringRef name) {
- return name.startswith(prefix) || name == prefix.drop_back();
-}
-
-StringRef elf::getOutputSectionName(const InputSectionBase *s) {
- if (config->relocatable)
- 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 (auto *isec = dyn_cast<InputSection>(s)) {
- if (InputSectionBase *rel = isec->getRelocatedSection()) {
- OutputSection *out = rel->getOutputSection();
- if (s->type == SHT_RELA)
- return saver.save(".rela" + out->name);
- return saver.save(".rel" + out->name);
- }
- }
-
- // A BssSection created for a common symbol is identified as "COMMON" in
- // linker scripts. It should go to .bss section.
- if (s->name == "COMMON")
- return ".bss";
-
- if (script->hasSectionsCommand)
- return s->name;
-
- // When no SECTIONS is specified, emulate GNU ld's internal linker scripts
- // by grouping sections with certain prefixes.
-
- // GNU ld places text sections with prefix ".text.hot.", ".text.unknown.",
- // ".text.unlikely.", ".text.startup." or ".text.exit." before others.
- // We provide an option -z keep-text-section-prefix to group such sections
- // into separate output sections. This is more flexible. See also
- // sortISDBySectionOrder().
- // ".text.unknown" means the hotness of the section is unknown. When
- // SampleFDO is used, if a function doesn't have sample, it could be very
- // cold or it could be a new function never being sampled. Those functions
- // will be kept in the ".text.unknown" section.
- // ".text.split." holds symbols which are split out from functions in other
- // input sections. For example, with -fsplit-machine-functions, placing the
- // cold parts in .text.split instead of .text.unlikely mitigates against poor
- // profile inaccuracy. Techniques such as hugepage remapping can make
- // conservative decisions at the section granularity.
- if (config->zKeepTextSectionPrefix)
- for (StringRef v : {".text.hot.", ".text.unknown.", ".text.unlikely.",
- ".text.startup.", ".text.exit.", ".text.split."})
- if (isSectionPrefix(v, s->name))
- return v.drop_back();
-
- 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."})
- if (isSectionPrefix(v, s->name))
- return v.drop_back();
-
- return s->name;
-}
-
static bool needsInterpSection() {
return !config->relocatable && !config->shared &&
!config->dynamicLinker.empty() && script->needsInterpSection();
@@ -332,8 +271,8 @@ void elf::addReservedSymbols() {
}
static OutputSection *findSection(StringRef name, unsigned partition = 1) {
- for (BaseCommand *base : script->sectionCommands)
- if (auto *sec = dyn_cast<OutputSection>(base))
+ for (SectionCommand *cmd : script->sectionCommands)
+ if (auto *sec = dyn_cast<OutputSection>(cmd))
if (sec->name == name && sec->partition == partition)
return sec;
return nullptr;
@@ -342,7 +281,10 @@ static OutputSection *findSection(StringRef name, unsigned partition = 1) {
template <class ELFT> void elf::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));
+ Out::tlsPhdr = nullptr;
+ Out::preinitArray = nullptr;
+ Out::initArray = nullptr;
+ Out::finiArray = nullptr;
// Add the .interp section first because it is not a SyntheticSection.
// The removeUnusedSyntheticSections() function relies on the
@@ -426,7 +368,6 @@ template <class ELFT> void elf::createSyntheticSections() {
make<RelocationSection<ELFT>>(relaDynName, config->zCombreloc);
if (config->hasDynSymTab) {
- part.dynSymTab = make<SymbolTableSection<ELFT>>(*part.dynStrTab);
add(part.dynSymTab);
part.verSym = make<VersionTableSection>();
@@ -624,9 +565,8 @@ template <class ELFT> void Writer<ELFT>::run() {
// --print-archive-stats=. Dump them before checkSections() because the files
// may be useful in case checkSections() or openFile() fails, for example, due
// to an erroneous file size.
- writeMapFile();
+ writeMapAndCref();
writeWhyExtract();
- writeCrossReferenceTable();
writeArchiveStats();
if (config->checkSections)
@@ -787,16 +727,16 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
// referring to a section (that happens if the section is a synthetic one), we
// don't create a section symbol for that section.
template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
- for (BaseCommand *base : script->sectionCommands) {
- auto *sec = dyn_cast<OutputSection>(base);
+ for (SectionCommand *cmd : script->sectionCommands) {
+ auto *sec = dyn_cast<OutputSection>(cmd);
if (!sec)
continue;
- auto i = llvm::find_if(sec->sectionCommands, [](BaseCommand *base) {
- if (auto *isd = dyn_cast<InputSectionDescription>(base))
+ auto i = llvm::find_if(sec->commands, [](SectionCommand *cmd) {
+ if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
return !isd->sections.empty();
return false;
});
- if (i == sec->sectionCommands.end())
+ if (i == sec->commands.end())
continue;
InputSectionBase *isec = cast<InputSectionDescription>(*i)->sections[0];
@@ -1053,7 +993,8 @@ static unsigned getSectionRank(const OutputSection *sec) {
return rank;
}
-static bool compareSections(const BaseCommand *aCmd, const BaseCommand *bCmd) {
+static bool compareSections(const SectionCommand *aCmd,
+ const SectionCommand *bCmd) {
const OutputSection *a = cast<OutputSection>(aCmd);
const OutputSection *b = cast<OutputSection>(bCmd);
@@ -1210,7 +1151,7 @@ static int getRankProximityAux(OutputSection *a, OutputSection *b) {
return countLeadingZeros(a->sortRank ^ b->sortRank);
}
-static int getRankProximity(OutputSection *a, BaseCommand *b) {
+static int getRankProximity(OutputSection *a, SectionCommand *b) {
auto *sec = dyn_cast<OutputSection>(b);
return (sec && sec->hasInputSections) ? getRankProximityAux(a, sec) : -1;
}
@@ -1229,7 +1170,7 @@ static int getRankProximity(OutputSection *a, BaseCommand *b) {
// /* The RW PT_LOAD starts here*/
// rw_sec : { *(rw_sec) }
// would mean that the RW PT_LOAD would become unaligned.
-static bool shouldSkip(BaseCommand *cmd) {
+static bool shouldSkip(SectionCommand *cmd) {
if (auto *assign = dyn_cast<SymbolAssignment>(cmd))
return assign->name != ".";
return false;
@@ -1238,13 +1179,13 @@ static bool shouldSkip(BaseCommand *cmd) {
// We want to place orphan sections so that they share as much
// characteristics with their neighbors as possible. For example, if
// both are rw, or both are tls.
-static std::vector<BaseCommand *>::iterator
-findOrphanPos(std::vector<BaseCommand *>::iterator b,
- std::vector<BaseCommand *>::iterator e) {
+static std::vector<SectionCommand *>::iterator
+findOrphanPos(std::vector<SectionCommand *>::iterator b,
+ std::vector<SectionCommand *>::iterator e) {
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) {
+ auto i = std::max_element(b, e, [=](SectionCommand *a, SectionCommand *b) {
return getRankProximity(sec, a) < getRankProximity(sec, b);
});
if (i == e)
@@ -1273,7 +1214,7 @@ findOrphanPos(std::vector<BaseCommand *>::iterator b,
break;
}
- auto isOutputSecWithInputSections = [](BaseCommand *cmd) {
+ auto isOutputSecWithInputSections = [](SectionCommand *cmd) {
auto *os = dyn_cast<OutputSection>(cmd);
return os && os->hasInputSections;
};
@@ -1482,7 +1423,7 @@ static void sortSection(OutputSection *sec,
// digit radix sort. The sections may be sorted stably again by a more
// significant key.
if (!order.empty())
- for (BaseCommand *b : sec->sectionCommands)
+ for (SectionCommand *b : sec->commands)
if (auto *isd = dyn_cast<InputSectionDescription>(b))
sortISDBySectionOrder(isd, order);
@@ -1499,8 +1440,8 @@ static void sortSection(OutputSection *sec,
// addressable range of [.got, .got + 0xFFFC] for GOT-relative relocations.
// To reduce the risk of relocation overflow, .toc contents are sorted so
// that sections having smaller relocation offsets are at beginning of .toc
- assert(sec->sectionCommands.size() == 1);
- auto *isd = cast<InputSectionDescription>(sec->sectionCommands[0]);
+ assert(sec->commands.size() == 1);
+ auto *isd = cast<InputSectionDescription>(sec->commands[0]);
llvm::stable_sort(isd->sections,
[](const InputSection *a, const InputSection *b) -> bool {
return a->file->ppc64SmallCodeModelTocRelocs &&
@@ -1515,8 +1456,8 @@ template <class ELFT> void Writer<ELFT>::sortInputSections() {
// Build the order once since it is expensive.
DenseMap<const InputSectionBase *, int> order = buildSectionOrder();
maybeShuffle(order);
- for (BaseCommand *base : script->sectionCommands)
- if (auto *sec = dyn_cast<OutputSection>(base))
+ for (SectionCommand *cmd : script->sectionCommands)
+ if (auto *sec = dyn_cast<OutputSection>(cmd))
sortSection(sec, order);
}
@@ -1531,8 +1472,8 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
sortInputSections();
- for (BaseCommand *base : script->sectionCommands) {
- auto *os = dyn_cast<OutputSection>(base);
+ for (SectionCommand *cmd : script->sectionCommands) {
+ auto *os = dyn_cast<OutputSection>(cmd);
if (!os)
continue;
os->sortRank = getSectionRank(os);
@@ -1547,7 +1488,9 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
if (!script->hasSectionsCommand) {
// We know that all the OutputSections are contiguous in this case.
- auto isSection = [](BaseCommand *base) { return isa<OutputSection>(base); };
+ auto isSection = [](SectionCommand *cmd) {
+ return isa<OutputSection>(cmd);
+ };
std::stable_sort(
llvm::find_if(script->sectionCommands, isSection),
llvm::find_if(llvm::reverse(script->sectionCommands), isSection).base(),
@@ -1602,8 +1545,8 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
auto i = script->sectionCommands.begin();
auto e = script->sectionCommands.end();
- auto nonScriptI = std::find_if(i, e, [](BaseCommand *base) {
- if (auto *sec = dyn_cast<OutputSection>(base))
+ auto nonScriptI = std::find_if(i, e, [](SectionCommand *cmd) {
+ if (auto *sec = dyn_cast<OutputSection>(cmd))
return sec->sectionIndex == UINT32_MAX;
return false;
});
@@ -1616,7 +1559,7 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
// the script with ". = 0xabcd" and the expectation is that every section is
// after that.
auto firstSectionOrDotAssignment =
- std::find_if(i, e, [](BaseCommand *cmd) { return !shouldSkip(cmd); });
+ std::find_if(i, e, [](SectionCommand *cmd) { return !shouldSkip(cmd); });
if (firstSectionOrDotAssignment != e &&
isa<SymbolAssignment>(**firstSectionOrDotAssignment))
++firstSectionOrDotAssignment;
@@ -1629,7 +1572,7 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
// 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) {
+ auto end = std::find_if(nonScriptI + 1, e, [=](SectionCommand *cmd) {
return cast<OutputSection>(cmd)->sortRank != rank;
});
std::rotate(pos, nonScriptI, end);
@@ -1670,8 +1613,8 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
// Sorting is performed separately.
std::vector<InputSection **> scriptSections;
std::vector<InputSection *> sections;
- for (BaseCommand *base : sec->sectionCommands) {
- auto *isd = dyn_cast<InputSectionDescription>(base);
+ for (SectionCommand *cmd : sec->commands) {
+ auto *isd = dyn_cast<InputSectionDescription>(cmd);
if (!isd)
continue;
bool hasLinkOrder = false;
@@ -1774,7 +1717,7 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
// If addrExpr is set, the address may not be a multiple of the alignment.
// Warn because this is error-prone.
- for (BaseCommand *cmd : script->sectionCommands)
+ for (SectionCommand *cmd : script->sectionCommands)
if (auto *os = dyn_cast<OutputSection>(cmd))
if (os->addr % os->alignment != 0)
warn("address (0x" + Twine::utohexstr(os->addr) + ") of section " +
@@ -1892,36 +1835,30 @@ static void removeUnusedSyntheticSections() {
})
.base();
- DenseSet<InputSectionDescription *> isdSet;
- // Mark unused synthetic sections for deletion
- auto end = std::stable_partition(
- start, inputSections.end(), [&](InputSectionBase *s) {
- SyntheticSection *ss = dyn_cast<SyntheticSection>(s);
- OutputSection *os = ss->getParent();
- if (!os || ss->isNeeded())
- return true;
-
- // If we reach here, then ss is an unused synthetic section and we want
- // to remove it from the corresponding input section description, and
- // orphanSections.
- for (BaseCommand *b : os->sectionCommands)
- if (auto *isd = dyn_cast<InputSectionDescription>(b))
- isdSet.insert(isd);
-
- llvm::erase_if(
- script->orphanSections,
- [=](const InputSectionBase *isec) { return isec == ss; });
-
- return false;
+ // Remove unused synthetic sections from inputSections;
+ DenseSet<InputSectionBase *> unused;
+ auto end =
+ std::remove_if(start, inputSections.end(), [&](InputSectionBase *s) {
+ auto *sec = cast<SyntheticSection>(s);
+ if (sec->getParent() && sec->isNeeded())
+ return false;
+ unused.insert(sec);
+ return true;
});
-
- DenseSet<InputSectionBase *> unused(end, inputSections.end());
- for (auto *isd : isdSet)
- llvm::erase_if(isd->sections,
- [=](InputSection *isec) { return unused.count(isec); });
-
- // Erase unused synthetic sections.
inputSections.erase(end, inputSections.end());
+
+ // Remove unused synthetic sections from the corresponding input section
+ // description and orphanSections.
+ for (auto *sec : unused)
+ if (OutputSection *osec = cast<SyntheticSection>(sec)->getParent())
+ for (SectionCommand *cmd : osec->commands)
+ if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
+ llvm::erase_if(isd->sections, [&](InputSection *isec) {
+ return unused.count(isec);
+ });
+ llvm::erase_if(script->orphanSections, [&](const InputSectionBase *sec) {
+ return unused.count(sec);
+ });
}
// Create output section objects and add them to OutputSections.
@@ -1935,8 +1872,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// addresses of each section by section name. Add such symbols.
if (!config->relocatable) {
addStartEndSymbols();
- for (BaseCommand *base : script->sectionCommands)
- if (auto *sec = dyn_cast<OutputSection>(base))
+ for (SectionCommand *cmd : script->sectionCommands)
+ if (auto *sec = dyn_cast<OutputSection>(cmd))
addStartStopSymbols(sec);
}
@@ -2087,11 +2024,14 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
sortSections();
- // Now that we have the final list, create a list of all the
- // OutputSections for convenience.
- for (BaseCommand *base : script->sectionCommands)
- if (auto *sec = dyn_cast<OutputSection>(base))
- outputSections.push_back(sec);
+ // Create a list of OutputSections, assign sectionIndex, and populate
+ // in.shStrTab.
+ for (SectionCommand *cmd : script->sectionCommands)
+ if (auto *osec = dyn_cast<OutputSection>(cmd)) {
+ outputSections.push_back(osec);
+ osec->sectionIndex = outputSections.size();
+ osec->shName = in.shStrTab->addString(osec->name);
+ }
// Prefer command line supplied address over other constraints.
for (OutputSection *sec : outputSections) {
@@ -2113,12 +2053,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// to 1 to make __ehdr_start defined. The section number is not
// particularly relevant.
Out::elfHeader->sectionIndex = 1;
-
- for (size_t i = 0, e = outputSections.size(); i != e; ++i) {
- OutputSection *sec = outputSections[i];
- sec->sectionIndex = i + 1;
- sec->shName = in.shStrTab->addString(sec->name);
- }
+ Out::elfHeader->size = sizeof(typename ELFT::Ehdr);
// Binary and relocatable output does not have PHDRS.
// The headers have to be created before finalize as that can influence the
@@ -2608,17 +2543,6 @@ static uint64_t computeFileOffset(OutputSection *os, uint64_t off) {
return first->offset + os->addr - first->addr;
}
-// Set an in-file position to a given section and returns the end position of
-// the section.
-static uint64_t setFileOffset(OutputSection *os, uint64_t off) {
- off = computeFileOffset(os, off);
- os->offset = off;
-
- if (os->type == SHT_NOBITS)
- return off;
- return off + os->size;
-}
-
template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
// Compute the minimum LMA of all non-empty non-NOBITS sections as minAddr.
auto needsOffset = [](OutputSection &sec) {
@@ -2646,9 +2570,8 @@ static std::string rangeToString(uint64_t addr, uint64_t len) {
// Assign file offsets to output sections.
template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
- uint64_t off = 0;
- off = setFileOffset(Out::elfHeader, off);
- off = setFileOffset(Out::programHeaders, off);
+ Out::programHeaders->offset = Out::elfHeader->size;
+ uint64_t off = Out::elfHeader->size + Out::programHeaders->size;
PhdrEntry *lastRX = nullptr;
for (Partition &part : partitions)
@@ -2661,18 +2584,23 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
for (OutputSection *sec : outputSections) {
if (!(sec->flags & SHF_ALLOC))
continue;
- off = setFileOffset(sec, off);
+ off = computeFileOffset(sec, off);
+ sec->offset = off;
+ if (sec->type != SHT_NOBITS)
+ off += sec->size;
// 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 (config->zSeparate != SeparateSegmentKind::None && lastRX &&
lastRX->lastSec == sec)
- off = alignTo(off, config->commonPageSize);
+ off = alignTo(off, config->maxPageSize);
}
- for (OutputSection *sec : outputSections)
- if (!(sec->flags & SHF_ALLOC))
- off = setFileOffset(sec, off);
+ for (OutputSection *osec : outputSections)
+ if (!(osec->flags & SHF_ALLOC)) {
+ osec->offset = alignTo(off, osec->alignment);
+ off = osec->offset + osec->size;
+ }
sectionHeaderOff = alignTo(off, config->wordsize);
fileSize = sectionHeaderOff + (outputSections.size() + 1) * sizeof(Elf_Shdr);
@@ -2946,9 +2874,9 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
for (PhdrEntry *p : part.phdrs)
if (p->p_type == PT_LOAD && (p->p_flags & PF_X))
fillTrap(Out::bufferStart + alignDown(p->firstSec->offset + p->p_filesz,
- config->commonPageSize),
+ config->maxPageSize),
Out::bufferStart + alignTo(p->firstSec->offset + p->p_filesz,
- config->commonPageSize));
+ config->maxPageSize));
// 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
@@ -2960,7 +2888,7 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
if (last && (last->p_flags & PF_X))
last->p_memsz = last->p_filesz =
- alignTo(last->p_filesz, config->commonPageSize);
+ alignTo(last->p_filesz, config->maxPageSize);
}
}
diff --git a/lld/ELF/Writer.h b/lld/ELF/Writer.h
index 3698544d977b..9c4a5b98451d 100644
--- a/lld/ELF/Writer.h
+++ b/lld/ELF/Writer.h
@@ -51,7 +51,6 @@ struct PhdrEntry {
};
void addReservedSymbols();
-llvm::StringRef getOutputSectionName(const InputSectionBase *s);
template <class ELFT> uint32_t calcMipsEFlags();