diff options
Diffstat (limited to 'lld/ELF')
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 *> §ionCommands) { +static SymbolAssignmentMap getSymbolAssignmentValues( + const std::vector<SectionCommand *> §ionCommands) { 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(); |