Reference reference
Each section has a relocate
method that can relocate itself.
It happens after the dot address resolution, phdrs creation.
Relocation for each relocatable section:
// lld/ELF/InputSection.h
// class InputSectionBase
// Each section knows how to relocate itself. These functions apply
// relocations, assuming that Buf points to this section's copy in
// the mmap'ed output buffer.
template <class ELFT> void relocate(uint8_t *buf, uint8_t *bufEnd);
void relocateAlloc(uint8_t *buf, uint8_t *bufEnd);
static uint64_t getRelocTargetVA(const InputFile *File, RelType Type,
relocateNoSym int64_t A, uint64_t P, const Symbol &Sym,
RelExpr Expr, InputSectionBase *isec,
uint64_t offset);
Call path for relocate
, relocateAlloc
and getRelocTargetVA
:
void InputSection::writeTo(uint8_t *buf)
=> relocate<ELFT>(buf, bufEnd);
=> adjustSplitStackFunctionPrologues<ELFT>(buf, bufEnd); // if (flags & SHF_EXECINSTR)
=> relocateAlloc(buf, bufEnd); // if (flags & SHF_ALLOC)
=> targetVA = getRelocTargetVA(file, type, rel.addend, addrLoc, *rel.sym, expr, this, rel.offset);
=> target->relocate(bufLoc, rel, targetVA);
=> relocateNonAllocForRelocatable(sec, buf); // if (config->relocatable)
=> sec->relocateNonAlloc<ELFT>(buf, sec->template relas<ELFT>()); // if (sec->areRelocsRela)
=> sec->relocateNonAlloc<ELFT>(buf, sec->template rels<ELFT>());
// call path to InputSection::writeTo
Relocation per target:
// lld/ELF/Target.h
// class TargetInfo
class TargetInfo{
...
virtual void relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const = 0;
void relocateNoSym(uint8_t *loc, RelType type, uint64_t val) const {
relocate(loc, Relocation{R_NONE, type, 0, 0, nullptr}, val);
}
}
// lld/ELF/Arch/Mips.cpp
class MIPS final: public TargetInfo{
...
void relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const override;
}
Call path for target relocate
// lld/ELF/InputSection.cpp
void InputSectionBase::relocate(uint8_t *buf, uint8_t *bufEnd)
=> static void relocateNonAllocForRelocatable(InputSection *sec, uint8_t *buf)
=> target->relocate(..)
void InputSectionBase::relocateAlloc(uint8_t *buf, uint8_t *bufEnd)
=> target->relocate(..)
call path for target relocateNoSym
:
void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels)
=> void TargetInfo::relocateNoSym(uint8_t *loc, RelType type, uint64_t val) const
=> this->relocate(...)
void ARMExidxSyntheticSection::writeTo(uint8_t *buf) // lld/ELF/SyntheticSections.cpp
=> void TargetInfo::relocateNoSym(uint8_t *loc, RelType type, uint64_t val) const
=> this->relocate(...)
// lld/ELF/Thunks.cpp
void ARMThunk::writeTo(uint8_t *buf)
void ThumbThunk::writeTo(uint8_t *buf)
void MipsThunk::writeTo(uint8_t *buf)
=> void TargetInfo::relocateNoSym(uint8_t *loc, RelType type, uint64_t val) const
=> this->relocate(...)
// lld/ELF/Arch/Mips.cpp
void MIPS<ELFT>::writePltHeader(uint8_t *buf) const
void MIPS<ELFT>::writePlt(uint8_t *buf, const Symbol &sym,
uint64_t pltEntryAddr) const
=> void TargetInfo::relocateNoSym(uint8_t *loc, RelType type, uint64_t val) const
=> this->relocate(...)
// lld/ELF/Arch/RISCV.cpp (recursive???)
void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const
=> void TargetInfo::relocateNoSym(uint8_t *loc, RelType type, uint64_t val) const
=> this->relocate(...)
Reference reference Synthetic Input Sections for relocation .got or .mipsgot are synthetic input sections created before relocation can actually happen on them. They are created before finalizeSections(), so that they can be placed into the finall output; they are updated during finalizeSections(), where they got allocated in the virtual space; After the location of sections are finalized, virtual addresses are mostly available for relocation to happen. Now here tracks the first step where synthetic relocation sections such as .
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?