diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -404,14 +404,82 @@ } } +namespace { +class Resolver { +public: + explicit Resolver(InputSectionBase &sec) + : sec(sec), config(elf::config.get()), target(*elf::target) { + if (auto *eh = dyn_cast(&sec)) + pieces = eh->pieces; + } + template void scanRelocs(ArrayRef rels); + +private: + InputSectionBase &sec; + const Configuration *const config; + const TargetInfo ⌖ + + // End of relocations. + const void *end = nullptr; + + // .eh_frame sections are mergeable input sections, so their input + // offsets are not linearly mapped to output section. For each input + // offset, we need to find a section piece containing the offset and + // add the piece's base address to the input offset to compute the + // output offset. That isn't cheap. + // + // The states are to speed up the offset computation. When we process + // relocations, we access offsets in the monotonically increasing + // order. So we can optimize for that access pattern. + ArrayRef pieces; + size_t i = 0; + + // Translates offsets in input sections to offsets in output sections. Given + // offset must increase monotonically. We assume that `pieces` is sorted by + // inputOff. + uint64_t getOffset(uint64_t off) { + if (pieces.empty()) + return off; + + while (i != pieces.size() && pieces[i].inputOff + pieces[i].size <= off) + ++i; + if (i == pieces.size()) + fatal(".eh_frame: relocation is not in any piece"); + + // Pieces must be contiguous, so there must be no holes in between. + assert(pieces[i].inputOff <= off && "Relocation not in any piece"); + + // Offset -1 means that the piece is dead (i.e. garbage collected). + if (pieces[i].outputOff == -1) + return -1; + return pieces[i].outputOff + off - pieces[i].inputOff; + } + + template RelType getMipsN32RelType(RelTy *&rel); + + template + int64_t computeMipsAddend(const RelTy &rel, RelExpr expr, bool isLocal); + + template + int64_t computeAddend(const RelTy &rel, RelExpr expr, bool isLocal); + + bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym, + uint64_t relOff); + + void processRelocAux(RelExpr expr, RelType type, uint64_t offset, Symbol &sym, + int64_t addend); + + template void scanReloc(RelTy *&i); +}; +} // namespace + // MIPS has an odd notion of "paired" relocations to calculate addends. // For example, if a relocation is of R_MIPS_HI16, there must be a // R_MIPS_LO16 relocation after that, and an addend is calculated using // the two relocations. template -static int64_t computeMipsAddend(const RelTy &rel, const RelTy *end, - InputSectionBase &sec, RelExpr expr, - bool isLocal) { +int64_t Resolver::computeMipsAddend(const RelTy &rel, RelExpr expr, + bool isLocal) { if (expr == R_MIPS_GOTREL && isLocal) return sec.getFile()->mipsGp0; @@ -430,10 +498,10 @@ // To make things worse, paired relocations might not be contiguous in // the relocation table, so we need to do linear search. *sigh* - for (const RelTy *ri = &rel; ri != end; ++ri) + for (const RelTy *ri = &rel; ri != static_cast(end); ++ri) if (ri->getType(config->isMips64EL) == pairTy && ri->getSymbol(config->isMips64EL) == symIndex) - return target->getImplicitAddend(buf + ri->r_offset, pairTy); + return target.getImplicitAddend(buf + ri->r_offset, pairTy); warn("can't find matching " + toString(pairTy) + " relocation for " + toString(type)); @@ -444,9 +512,7 @@ // is in a relocation itself. If it is REL, we need to read it from an // input section. template -static int64_t computeAddend(const RelTy &rel, const RelTy *end, - InputSectionBase &sec, RelExpr expr, - bool isLocal) { +int64_t Resolver::computeAddend(const RelTy &rel, RelExpr expr, bool isLocal) { int64_t addend; RelType type = rel.getType(config->isMips64EL); @@ -454,13 +520,13 @@ addend = getAddend(rel); } else { const uint8_t *buf = sec.data().data(); - addend = target->getImplicitAddend(buf + rel.r_offset, type); + addend = target.getImplicitAddend(buf + rel.r_offset, type); } if (config->emachine == EM_PPC64 && config->isPic && type == R_PPC64_TOC) addend += getPPC64TocBase(); if (config->emachine == EM_MIPS) - addend += computeMipsAddend(rel, end, sec, expr, isLocal); + addend += computeMipsAddend(rel, expr, isLocal); return addend; } @@ -777,62 +843,16 @@ // packs all relocations into the single relocation record. Here we emulate // this for the N32 ABI. Iterate over relocation with the same offset and put // theirs types into the single bit-set. -template static RelType getMipsN32RelType(RelTy *&rel, RelTy *end) { +template RelType Resolver::getMipsN32RelType(RelTy *&rel) { RelType type = 0; uint64_t offset = rel->r_offset; int n = 0; - while (rel != end && rel->r_offset == offset) + while (rel != static_cast(end) && rel->r_offset == offset) type |= (rel++)->getType(config->isMips64EL) << (8 * n++); return type; } -// .eh_frame sections are mergeable input sections, so their input -// offsets are not linearly mapped to output section. For each input -// offset, we need to find a section piece containing the offset and -// add the piece's base address to the input offset to compute the -// output offset. That isn't cheap. -// -// This class is to speed up the offset computation. When we process -// relocations, we access offsets in the monotonically increasing -// order. So we can optimize for that access pattern. -// -// For sections other than .eh_frame, this class doesn't do anything. -namespace { -class OffsetGetter { -public: - explicit OffsetGetter(InputSectionBase &sec) { - if (auto *eh = dyn_cast(&sec)) - pieces = eh->pieces; - } - - // Translates offsets in input sections to offsets in output sections. - // Given offset must increase monotonically. We assume that Piece is - // sorted by inputOff. - uint64_t get(uint64_t off) { - if (pieces.empty()) - return off; - - while (i != pieces.size() && pieces[i].inputOff + pieces[i].size <= off) - ++i; - if (i == pieces.size()) - fatal(".eh_frame: relocation is not in any piece"); - - // Pieces must be contiguous, so there must be no holes in between. - assert(pieces[i].inputOff <= off && "Relocation not in any piece"); - - // Offset -1 means that the piece is dead (i.e. garbage collected). - if (pieces[i].outputOff == -1) - return -1; - return pieces[i].outputOff + off - pieces[i].inputOff; - } - -private: - ArrayRef pieces; - size_t i = 0; -}; -} // namespace - static void addRelativeReloc(InputSectionBase &isec, uint64_t offsetInSec, Symbol &sym, int64_t addend, RelExpr expr, RelType type) { @@ -924,8 +944,8 @@ // // If this function returns false, that means we need to emit a // dynamic relocation so that the relocation will be fixed at load-time. -static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym, - InputSectionBase &s, uint64_t relOff) { +bool Resolver::isStaticLinkTimeConstant(RelExpr e, RelType type, + const Symbol &sym, uint64_t relOff) { // These expressions always compute a constant if (oneofusesOnlyLowPageBits(type) || !config->isPic; + return target.usesOnlyLowPageBits(type) || !config->isPic; if (sym.isPreemptible) return false; @@ -957,7 +977,7 @@ if (!absVal && relE) return true; if (!absVal && !relE) - return target->usesOnlyLowPageBits(type); + return target.usesOnlyLowPageBits(type); assert(absVal && relE); @@ -975,7 +995,7 @@ return true; error("relocation " + toString(type) + " cannot refer to absolute symbol: " + - toString(sym) + getLocation(s, sym, relOff)); + toString(sym) + getLocation(sec, sym, relOff)); return true; } @@ -992,9 +1012,8 @@ // sections. Given that it is ro, we will need an extra PT_LOAD. This // complicates things for the dynamic linker and means we would have to reserve // space for the extra PT_LOAD even if we end up not using it. -template -static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type, - uint64_t offset, Symbol &sym, int64_t addend) { +void Resolver::processRelocAux(RelExpr expr, RelType type, uint64_t offset, + Symbol &sym, int64_t addend) { // If the relocation is known to be a link-time constant, we know no dynamic // relocation will be created, pass the control to relocateAlloc() or // relocateNonAlloc() to resolve it. @@ -1009,7 +1028,7 @@ // -shared matches the spirit of its -z undefs default. -pie has freedom on // choices, and we choose dynamic relocations to be consistent with the // handling of GOT-generating relocations. - if (isStaticLinkTimeConstant(expr, type, sym, sec, offset) || + if (isStaticLinkTimeConstant(expr, type, sym, offset) || (!config->isPic && sym.isUndefWeak())) { sec.relocations.push_back({expr, type, offset, addend, &sym}); return; @@ -1017,13 +1036,13 @@ bool canWrite = (sec.flags & SHF_WRITE) || !config->zText; if (canWrite) { - RelType rel = target->getDynRel(type); - if (expr == R_GOT || (rel == target->symbolicRel && !sym.isPreemptible)) { + RelType rel = target.getDynRel(type); + if (expr == R_GOT || (rel == target.symbolicRel && !sym.isPreemptible)) { addRelativeReloc(sec, offset, sym, addend, expr, type); return; } else if (rel != 0) { - if (config->emachine == EM_MIPS && rel == target->symbolicRel) - rel = target->relativeRel; + if (config->emachine == EM_MIPS && rel == target.symbolicRel) + rel = target.relativeRel; sec.getPartition().relaDyn->addSymbolReloc(rel, sec, offset, sym, addend, type); @@ -1261,24 +1280,22 @@ return 0; } -template -static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i, - RelTy *end) { +template void Resolver::scanReloc(RelTy *&i) { const RelTy &rel = *i; - uint32_t symIndex = rel.getSymbol(config->isMips64EL); + uint32_t symIndex = rel.getSymbol(0); Symbol &sym = sec.getFile()->getSymbol(symIndex); RelType type; // Deal with MIPS oddity. if (config->mipsN32Abi) { - type = getMipsN32RelType(i, end); + type = getMipsN32RelType(i); } else { type = rel.getType(config->isMips64EL); ++i; } // Get an offset in an output section this relocation is applied to. - uint64_t offset = getOffset.get(rel.r_offset); + uint64_t offset = getOffset(rel.r_offset); if (offset == uint64_t(-1)) return; @@ -1289,14 +1306,14 @@ return; const uint8_t *relocatedAddr = sec.data().begin() + rel.r_offset; - RelExpr expr = target->getRelExpr(type, sym, relocatedAddr); + RelExpr expr = target.getRelExpr(type, sym, relocatedAddr); // Ignore R_*_NONE and other marker relocations. if (expr == R_NONE) return; // Read an addend. - int64_t addend = computeAddend(rel, end, sec, expr, sym.isLocal()); + int64_t addend = computeAddend(rel, expr, sym.isLocal()); if (config->emachine == EM_PPC64) { // We can separate the small code model relocations into 2 categories: @@ -1381,7 +1398,7 @@ type == R_HEX_GD_PLT_B32_PCREL_X))) expr = fromPlt(expr); } else if (!isAbsoluteValue(sym)) { - expr = target->adjustGotPcExpr(type, addend, relocatedAddr); + expr = target.adjustGotPcExpr(type, addend, relocatedAddr); } } @@ -1412,7 +1429,7 @@ sym.hasDirectReloc = true; } - processRelocAux(sec, expr, type, offset, sym, addend); + processRelocAux(expr, type, offset, sym, addend); } // R_PPC64_TLSGD/R_PPC64_TLSLD is required to mark `bl __tls_get_addr` for @@ -1453,9 +1470,7 @@ } template -static void scanRelocs(InputSectionBase &sec, ArrayRef rels) { - OffsetGetter getOffset(sec); - +void Resolver::scanRelocs(ArrayRef rels) { // Not all relocations end up in Sec.Relocations, but a lot do. sec.relocations.reserve(rels.size()); @@ -1469,8 +1484,9 @@ if (isa(sec)) rels = sortRels(rels, storage); - for (auto i = rels.begin(), end = rels.end(); i != end;) - scanReloc(sec, getOffset, i, end); + end = static_cast(rels.end()); + for (auto i = rels.begin(); i != end;) + scanReloc(i); // Sort relocations by offset for more efficient searching for // R_RISCV_PCREL_HI20 and R_PPC64_ADDR64. @@ -1483,11 +1499,12 @@ } template void elf::scanRelocations(InputSectionBase &s) { + Resolver resolver(s); const RelsOrRelas rels = s.template relsOrRelas(); if (rels.areRelocsRel()) - scanRelocs(s, rels.rels); + resolver.template scanRelocs(rels.rels); else - scanRelocs(s, rels.relas); + resolver.template scanRelocs(rels.relas); } static bool handleNonPreemptibleIfunc(Symbol &sym) {