aboutsummaryrefslogtreecommitdiff
path: root/lld/ELF/Relocations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/Relocations.cpp')
-rw-r--r--lld/ELF/Relocations.cpp131
1 files changed, 62 insertions, 69 deletions
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index bd96c05..84b9b5e 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -6,37 +6,22 @@
//
//===----------------------------------------------------------------------===//
//
-// This file contains platform-independent functions to process relocations.
-// I'll describe the overview of this file here.
+// This file implements the core relocation processing logic. It analyzes
+// relocations and determines what auxiliary data structures (GOT, PLT, copy
+// relocations) need to be created during linking.
//
-// Simple relocations are easy to handle for the linker. For example,
-// for R_X86_64_PC64 relocs, the linker just has to fix up locations
-// with the relative offsets to the target symbols. It would just be
-// reading records from relocation sections and applying them to output.
+// The main entry point is scanRelocations<ELFT>(), which calls scanSection()
+// to process all relocations within an input section. For each relocation,
+// scan() analyzes the type and target, and determines whether a synthetic
+// section entry or dynamic relocation is needed.
//
-// But not all relocations are that easy to handle. For example, for
-// R_386_GOTOFF relocs, the linker has to create new GOT entries for
-// symbols if they don't exist, and fix up locations with GOT entry
-// offsets from the beginning of GOT section. So there is more than
-// fixing addresses in relocation processing.
+// Note: This file analyzes what needs to be done but doesn't apply the
+// actual relocations - that happens later in InputSection::writeTo().
+// Instead, it populates Relocation objects in InputSectionBase::relocations
+// and creates necessary synthetic sections (GOT, PLT, etc.).
//
-// ELF defines a large number of complex relocations.
-//
-// The functions in this file analyze relocations and do whatever needs
-// to be done. It includes, but not limited to, the following.
-//
-// - create GOT/PLT entries
-// - create new relocations in .dynsym to let the dynamic linker resolve
-// them at runtime (since ELF supports dynamic linking, not all
-// relocations can be resolved at link-time)
-// - create COPY relocs and reserve space in .bss
-// - replace expensive relocs (in terms of runtime cost) with cheap ones
-// - error out infeasible combinations such as PIC and non-relative relocs
-//
-// Note that the functions in this file don't actually apply relocations
-// because it doesn't know about the output file nor the output file buffer.
-// It instead stores Relocation objects to InputSection's Relocations
-// vector to let it apply later in InputSection::writeTo.
+// In addition, this file implements the core Thunk creation logic, called
+// during finalizeAddressDependentContent().
//
//===----------------------------------------------------------------------===//
@@ -405,22 +390,17 @@ namespace {
class OffsetGetter {
public:
OffsetGetter() = default;
- explicit OffsetGetter(InputSectionBase &sec) {
- if (auto *eh = dyn_cast<EhInputSection>(&sec)) {
- cies = eh->cies;
- fdes = eh->fdes;
- i = cies.begin();
- j = fdes.begin();
- }
+ explicit OffsetGetter(EhInputSection &sec) {
+ cies = sec.cies;
+ fdes = sec.fdes;
+ i = cies.begin();
+ j = fdes.begin();
}
// 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(Ctx &ctx, uint64_t off) {
- if (cies.empty())
- return off;
-
while (j != fdes.end() && j->inputOff <= off)
++j;
auto it = j;
@@ -450,13 +430,12 @@ private:
class RelocationScanner {
public:
RelocationScanner(Ctx &ctx) : ctx(ctx) {}
- template <class ELFT>
- void scanSection(InputSectionBase &s, bool isEH = false);
+ template <class ELFT> void scanSection(InputSectionBase &s);
+ template <class ELFT> void scanEhSection(EhInputSection &s);
private:
Ctx &ctx;
InputSectionBase *sec;
- OffsetGetter getter;
// End of relocations, used by Mips/PPC64.
const void *end = nullptr;
@@ -466,14 +445,14 @@ private:
int64_t computeMipsAddend(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;
+ void process(RelExpr expr, RelType type, uint64_t offset, Symbol &sym,
+ int64_t addend) const;
unsigned handleTlsRelocation(RelExpr expr, RelType type, uint64_t offset,
Symbol &sym, int64_t addend);
template <class ELFT, class RelTy>
- void scanOne(typename Relocs<RelTy>::const_iterator &i);
- template <class ELFT, class RelTy> void scan(Relocs<RelTy> rels);
+ void scan(typename Relocs<RelTy>::const_iterator &i);
+ template <class ELFT, class RelTy> void scanSectionImpl(Relocs<RelTy> rels);
};
} // namespace
@@ -961,7 +940,7 @@ static bool canDefineSymbolInExecutable(Ctx &ctx, Symbol &sym) {
}
// Returns true if a given relocation can be computed at link-time.
-// This only handles relocation types expected in processAux.
+// This only handles relocation types expected in process().
//
// For instance, we know the offset from a relocation to its target at
// link-time if the relocation is PC-relative and refers a
@@ -1052,8 +1031,8 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
// 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.
-void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
- Symbol &sym, int64_t addend) const {
+void RelocationScanner::process(RelExpr expr, RelType type, uint64_t offset,
+ Symbol &sym, int64_t addend) const {
// If non-ifunc non-preemptible, change PLT to direct call and optimize GOT
// indirection.
const bool isIfunc = sym.isGnuIFunc();
@@ -1493,7 +1472,7 @@ unsigned RelocationScanner::handleTlsRelocation(RelExpr expr, RelType type,
}
template <class ELFT, class RelTy>
-void RelocationScanner::scanOne(typename Relocs<RelTy>::const_iterator &i) {
+void RelocationScanner::scan(typename Relocs<RelTy>::const_iterator &i) {
const RelTy &rel = *i;
uint32_t symIndex = rel.getSymbol(ctx.arg.isMips64EL);
Symbol &sym = sec->getFile<ELFT>()->getSymbol(symIndex);
@@ -1511,9 +1490,7 @@ void RelocationScanner::scanOne(typename Relocs<RelTy>::const_iterator &i) {
}
}
// Get an offset in an output section this relocation is applied to.
- uint64_t offset = getter.get(ctx, rel.r_offset);
- if (offset == uint64_t(-1))
- return;
+ uint64_t offset = rel.r_offset;
RelExpr expr =
ctx.target->getRelExpr(type, sym, sec->content().data() + offset);
@@ -1587,7 +1564,7 @@ void RelocationScanner::scanOne(typename Relocs<RelTy>::const_iterator &i) {
}
// Process TLS relocations, including TLS optimizations. Note that
- // R_TPREL and R_TPREL_NEG relocations are resolved in processAux.
+ // R_TPREL and R_TPREL_NEG relocations are resolved in process().
//
// Some RISCV TLSDESC relocations reference a local NOTYPE symbol,
// but we need to process them in handleTlsRelocation.
@@ -1599,7 +1576,7 @@ void RelocationScanner::scanOne(typename Relocs<RelTy>::const_iterator &i) {
}
}
- processAux(expr, type, offset, sym, addend);
+ process(expr, type, offset, sym, addend);
}
// R_PPC64_TLSGD/R_PPC64_TLSLD is required to mark `bl __tls_get_addr` for
@@ -1642,30 +1619,27 @@ static void checkPPC64TLSRelax(InputSectionBase &sec, Relocs<RelTy> rels) {
}
template <class ELFT, class RelTy>
-void RelocationScanner::scan(Relocs<RelTy> rels) {
+void RelocationScanner::scanSectionImpl(Relocs<RelTy> rels) {
// Not all relocations end up in Sec->Relocations, but a lot do.
sec->relocations.reserve(rels.size());
if (ctx.arg.emachine == EM_PPC64)
checkPPC64TLSRelax<RelTy>(*sec, rels);
- // For EhInputSection, OffsetGetter expects the relocations to be sorted by
- // r_offset. In rare cases (.eh_frame pieces are reordered by a linker
- // script), the relocations may be unordered.
// On SystemZ, all sections need to be sorted by r_offset, to allow TLS
// relaxation to be handled correctly - see SystemZ::getTlsGdRelaxSkip.
SmallVector<RelTy, 0> storage;
- if (isa<EhInputSection>(sec) || ctx.arg.emachine == EM_S390)
+ if (ctx.arg.emachine == EM_S390)
rels = sortRels(rels, storage);
if constexpr (RelTy::IsCrel) {
for (auto i = rels.begin(); i != rels.end();)
- scanOne<ELFT, RelTy>(i);
+ scan<ELFT, RelTy>(i);
} else {
// The non-CREL code path has additional check for PPC64 TLS.
end = static_cast<const void *>(rels.end());
for (auto i = rels.begin(); i != end;)
- scanOne<ELFT, RelTy>(i);
+ scan<ELFT, RelTy>(i);
}
// Sort relocations by offset for more efficient searching for
@@ -1680,17 +1654,36 @@ void RelocationScanner::scan(Relocs<RelTy> rels) {
});
}
-template <class ELFT>
-void RelocationScanner::scanSection(InputSectionBase &s, bool isEH) {
+template <class ELFT> void RelocationScanner::scanSection(InputSectionBase &s) {
sec = &s;
- getter = OffsetGetter(s);
- const RelsOrRelas<ELFT> rels = s.template relsOrRelas<ELFT>(!isEH);
+ const RelsOrRelas<ELFT> rels = s.template relsOrRelas<ELFT>();
if (rels.areRelocsCrel())
- scan<ELFT>(rels.crels);
+ scanSectionImpl<ELFT>(rels.crels);
else if (rels.areRelocsRel())
- scan<ELFT>(rels.rels);
+ scanSectionImpl<ELFT>(rels.rels);
else
- scan<ELFT>(rels.relas);
+ scanSectionImpl<ELFT>(rels.relas);
+}
+
+template <class ELFT> void RelocationScanner::scanEhSection(EhInputSection &s) {
+ sec = &s;
+ OffsetGetter getter(s);
+ auto rels = s.rels;
+ s.relocations.reserve(rels.size());
+ for (auto &r : rels) {
+ // Ignore R_*_NONE and other marker relocations.
+ if (r.expr == R_NONE)
+ continue;
+ uint64_t offset = getter.get(ctx, r.offset);
+ // Skip if the relocation offset is within a dead piece.
+ if (offset == uint64_t(-1))
+ continue;
+ Symbol *sym = r.sym;
+ if (sym->isUndefined() &&
+ maybeReportUndefined(ctx, cast<Undefined>(*sym), *sec, offset))
+ continue;
+ process(r.expr, r.type, offset, *sym, r.addend);
+ }
}
template <class ELFT> void elf::scanRelocations(Ctx &ctx) {
@@ -1725,7 +1718,7 @@ template <class ELFT> void elf::scanRelocations(Ctx &ctx) {
RelocationScanner scanner(ctx);
for (Partition &part : ctx.partitions) {
for (EhInputSection *sec : part.ehFrame->sections)
- scanner.template scanSection<ELFT>(*sec, /*isEH=*/true);
+ scanner.template scanEhSection<ELFT>(*sec);
if (part.armExidx && part.armExidx->isLive())
for (InputSection *sec : part.armExidx->exidxSections)
if (sec->isLive())