Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 29 additions & 44 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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().
//
//===----------------------------------------------------------------------===//

Expand Down Expand Up @@ -466,14 +451,14 @@ class RelocationScanner {
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

Expand Down Expand Up @@ -961,7 +946,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
Expand Down Expand Up @@ -1052,8 +1037,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();
Expand Down Expand Up @@ -1493,7 +1478,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);
Expand Down Expand Up @@ -1587,7 +1572,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.
Expand All @@ -1599,7 +1584,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
Expand Down Expand Up @@ -1642,7 +1627,7 @@ 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());

Expand All @@ -1660,12 +1645,12 @@ void RelocationScanner::scan(Relocs<RelTy> rels) {

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
Expand All @@ -1686,11 +1671,11 @@ void RelocationScanner::scanSection(InputSectionBase &s, bool isEH) {
getter = OffsetGetter(s);
const RelsOrRelas<ELFT> rels = s.template relsOrRelas<ELFT>(!isEH);
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 elf::scanRelocations(Ctx &ctx) {
Expand Down
Loading