mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-15 04:29:42 +00:00
[ELF] Add RelocationScanner. NFC
Currently the way some relocation-related static functions pass around states is clumsy. Add a Resolver class to store some states as member variables. Advantages: * Avoid the parameter `InputSectionBase &sec` (this offsets the cost passing around `this` paramemter) * Avoid the parameter `end` (Mips and PowerPC hacks) * `config` and `target` can be cached as member variables to reduce global state accesses. (potential speedup because the compiler didn't know `config`/`target` were not changed across function calls) * If we ever want to reduce if-else costs (e.g. `config->emachine==EM_MIPS` for non-Mips) or introduce parallel relocation scan not handling some tricky arches (PPC/Mips), we can templatize Resolver `target` isn't used as much as `config`, so I change it to a const reference during the migration. There is a minor performance inprovement for elf::scanRelocations. Reviewed By: ikudrin, peter.smith Differential Revision: https://reviews.llvm.org/D116881
This commit is contained in:
parent
b22a93f4fb
commit
37a1291885
@ -447,6 +447,36 @@ private:
|
||||
ArrayRef<EhSectionPiece> pieces;
|
||||
size_t i = 0;
|
||||
};
|
||||
|
||||
// This class encapsulates states needed to scan relocations for one
|
||||
// InputSectionBase.
|
||||
class RelocationScanner {
|
||||
public:
|
||||
explicit RelocationScanner(InputSectionBase &sec)
|
||||
: sec(sec), getter(sec), config(elf::config.get()), target(*elf::target) {
|
||||
}
|
||||
template <class ELFT, class RelTy> void scan(ArrayRef<RelTy> rels);
|
||||
|
||||
private:
|
||||
InputSectionBase &sec;
|
||||
OffsetGetter getter;
|
||||
const Configuration *const config;
|
||||
const TargetInfo ⌖
|
||||
|
||||
// End of relocations, used by Mips/PPC64.
|
||||
const void *end = nullptr;
|
||||
|
||||
template <class RelTy> RelType getMipsN32RelType(RelTy *&rel) const;
|
||||
template <class ELFT, class RelTy>
|
||||
int64_t computeMipsAddend(const RelTy &rel, RelExpr expr, bool isLocal) const;
|
||||
template <class ELFT, class RelTy>
|
||||
int64_t computeAddend(const RelTy &rel, RelExpr expr, bool isLocal) const;
|
||||
bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym,
|
||||
uint64_t relOff) const;
|
||||
void processAux(RelExpr expr, RelType type, uint64_t offset, Symbol &sym,
|
||||
int64_t addend) const;
|
||||
template <class ELFT, class RelTy> void scanOne(RelTy *&i);
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// MIPS has an odd notion of "paired" relocations to calculate addends.
|
||||
@ -454,9 +484,8 @@ private:
|
||||
// R_MIPS_LO16 relocation after that, and an addend is calculated using
|
||||
// the two relocations.
|
||||
template <class ELFT, class RelTy>
|
||||
static int64_t computeMipsAddend(const RelTy &rel, const RelTy *end,
|
||||
InputSectionBase &sec, RelExpr expr,
|
||||
bool isLocal) {
|
||||
int64_t RelocationScanner::computeMipsAddend(const RelTy &rel, RelExpr expr,
|
||||
bool isLocal) const {
|
||||
if (expr == R_MIPS_GOTREL && isLocal)
|
||||
return sec.getFile<ELFT>()->mipsGp0;
|
||||
|
||||
@ -475,10 +504,10 @@ static int64_t computeMipsAddend(const RelTy &rel, const RelTy *end,
|
||||
|
||||
// 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<const RelTy *>(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));
|
||||
@ -489,9 +518,8 @@ static int64_t computeMipsAddend(const RelTy &rel, const RelTy *end,
|
||||
// is in a relocation itself. If it is REL, we need to read it from an
|
||||
// input section.
|
||||
template <class ELFT, class RelTy>
|
||||
static int64_t computeAddend(const RelTy &rel, const RelTy *end,
|
||||
InputSectionBase &sec, RelExpr expr,
|
||||
bool isLocal) {
|
||||
int64_t RelocationScanner::computeAddend(const RelTy &rel, RelExpr expr,
|
||||
bool isLocal) const {
|
||||
int64_t addend;
|
||||
RelType type = rel.getType(config->isMips64EL);
|
||||
|
||||
@ -499,13 +527,13 @@ static int64_t computeAddend(const RelTy &rel, const RelTy *end,
|
||||
addend = getAddend<ELFT>(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<ELFT>(rel, end, sec, expr, isLocal);
|
||||
addend += computeMipsAddend<ELFT>(rel, expr, isLocal);
|
||||
|
||||
return addend;
|
||||
}
|
||||
@ -822,12 +850,13 @@ static bool maybeReportUndefined(Symbol &sym, InputSectionBase &sec,
|
||||
// packs all relocations into the single relocation record. Here we emulate
|
||||
// this for the N32 ABI. Iterate over relocation with the same offset and put
|
||||
// theirs types into the single bit-set.
|
||||
template <class RelTy> static RelType getMipsN32RelType(RelTy *&rel, RelTy *end) {
|
||||
template <class RelTy>
|
||||
RelType RelocationScanner::getMipsN32RelType(RelTy *&rel) const {
|
||||
RelType type = 0;
|
||||
uint64_t offset = rel->r_offset;
|
||||
|
||||
int n = 0;
|
||||
while (rel != end && rel->r_offset == offset)
|
||||
while (rel != static_cast<const RelTy *>(end) && rel->r_offset == offset)
|
||||
type |= (rel++)->getType(config->isMips64EL) << (8 * n++);
|
||||
return type;
|
||||
}
|
||||
@ -923,8 +952,9 @@ static bool canDefineSymbolInExecutable(Symbol &sym) {
|
||||
//
|
||||
// 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 RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
|
||||
const Symbol &sym,
|
||||
uint64_t relOff) const {
|
||||
// These expressions always compute a constant
|
||||
if (oneof<R_GOTPLT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL,
|
||||
R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
|
||||
@ -936,7 +966,7 @@ static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym,
|
||||
// These never do, except if the entire file is position dependent or if
|
||||
// only the low bits are used.
|
||||
if (e == R_GOT || e == R_PLT)
|
||||
return target->usesOnlyLowPageBits(type) || !config->isPic;
|
||||
return target.usesOnlyLowPageBits(type) || !config->isPic;
|
||||
|
||||
if (sym.isPreemptible)
|
||||
return false;
|
||||
@ -956,7 +986,7 @@ static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym,
|
||||
if (!absVal && relE)
|
||||
return true;
|
||||
if (!absVal && !relE)
|
||||
return target->usesOnlyLowPageBits(type);
|
||||
return target.usesOnlyLowPageBits(type);
|
||||
|
||||
assert(absVal && relE);
|
||||
|
||||
@ -974,7 +1004,7 @@ static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym,
|
||||
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;
|
||||
}
|
||||
|
||||
@ -991,9 +1021,8 @@ static bool isStaticLinkTimeConstant(RelExpr e, RelType type, const Symbol &sym,
|
||||
// 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 <class ELFT>
|
||||
static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
|
||||
uint64_t offset, Symbol &sym, int64_t addend) {
|
||||
void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
|
||||
Symbol &sym, int64_t addend) const {
|
||||
// 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.
|
||||
@ -1008,7 +1037,7 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
|
||||
// -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;
|
||||
@ -1016,13 +1045,13 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
|
||||
|
||||
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);
|
||||
|
||||
@ -1260,9 +1289,7 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym,
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class ELFT, class RelTy>
|
||||
static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
|
||||
RelTy *end) {
|
||||
template <class ELFT, class RelTy> void RelocationScanner::scanOne(RelTy *&i) {
|
||||
const RelTy &rel = *i;
|
||||
uint32_t symIndex = rel.getSymbol(config->isMips64EL);
|
||||
Symbol &sym = sec.getFile<ELFT>()->getSymbol(symIndex);
|
||||
@ -1270,14 +1297,14 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
|
||||
|
||||
// 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 = getter.get(rel.r_offset);
|
||||
if (offset == uint64_t(-1))
|
||||
return;
|
||||
|
||||
@ -1288,14 +1315,14 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
|
||||
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<ELFT>(rel, end, sec, expr, sym.isLocal());
|
||||
int64_t addend = computeAddend<ELFT>(rel, expr, sym.isLocal());
|
||||
|
||||
if (config->emachine == EM_PPC64) {
|
||||
// We can separate the small code model relocations into 2 categories:
|
||||
@ -1344,7 +1371,7 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
|
||||
}
|
||||
|
||||
// Process TLS relocations, including relaxing TLS relocations. Note that
|
||||
// R_TPREL and R_TPREL_NEG relocations are resolved in processRelocAux.
|
||||
// R_TPREL and R_TPREL_NEG relocations are resolved in processAux.
|
||||
if (expr == R_TPREL || expr == R_TPREL_NEG) {
|
||||
if (config->shared) {
|
||||
errorOrWarn("relocation " + toString(type) + " against " + toString(sym) +
|
||||
@ -1380,7 +1407,7 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1411,7 +1438,7 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
|
||||
sym.hasDirectReloc = true;
|
||||
}
|
||||
|
||||
processRelocAux<ELFT>(sec, expr, type, offset, sym, addend);
|
||||
processAux(expr, type, offset, sym, addend);
|
||||
}
|
||||
|
||||
// R_PPC64_TLSGD/R_PPC64_TLSLD is required to mark `bl __tls_get_addr` for
|
||||
@ -1452,9 +1479,7 @@ static void checkPPC64TLSRelax(InputSectionBase &sec, ArrayRef<RelTy> rels) {
|
||||
}
|
||||
|
||||
template <class ELFT, class RelTy>
|
||||
static void scanRelocs(InputSectionBase &sec, ArrayRef<RelTy> rels) {
|
||||
OffsetGetter getOffset(sec);
|
||||
|
||||
void RelocationScanner::scan(ArrayRef<RelTy> rels) {
|
||||
// Not all relocations end up in Sec.Relocations, but a lot do.
|
||||
sec.relocations.reserve(rels.size());
|
||||
|
||||
@ -1468,8 +1493,9 @@ static void scanRelocs(InputSectionBase &sec, ArrayRef<RelTy> rels) {
|
||||
if (isa<EhInputSection>(sec))
|
||||
rels = sortRels(rels, storage);
|
||||
|
||||
for (auto i = rels.begin(), end = rels.end(); i != end;)
|
||||
scanReloc<ELFT>(sec, getOffset, i, end);
|
||||
end = static_cast<const void *>(rels.end());
|
||||
for (auto i = rels.begin(); i != end;)
|
||||
scanOne<ELFT>(i);
|
||||
|
||||
// Sort relocations by offset for more efficient searching for
|
||||
// R_RISCV_PCREL_HI20 and R_PPC64_ADDR64.
|
||||
@ -1482,11 +1508,12 @@ static void scanRelocs(InputSectionBase &sec, ArrayRef<RelTy> rels) {
|
||||
}
|
||||
|
||||
template <class ELFT> void elf::scanRelocations(InputSectionBase &s) {
|
||||
RelocationScanner scanner(s);
|
||||
const RelsOrRelas<ELFT> rels = s.template relsOrRelas<ELFT>();
|
||||
if (rels.areRelocsRel())
|
||||
scanRelocs<ELFT>(s, rels.rels);
|
||||
scanner.template scan<ELFT>(rels.rels);
|
||||
else
|
||||
scanRelocs<ELFT>(s, rels.relas);
|
||||
scanner.template scan<ELFT>(rels.relas);
|
||||
}
|
||||
|
||||
static bool handleNonPreemptibleIfunc(Symbol &sym) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user