Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 4 additions & 0 deletions lld/ELF/Arch/Mips.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ template <class ELFT> class MIPS final : public TargetInfo {
};
} // namespace

uint64_t elf::getMipsPageAddr(uint64_t addr) {
return (addr + 0x8000) & ~0xffff;
}

template <class ELFT> MIPS<ELFT>::MIPS(Ctx &ctx) : TargetInfo(ctx) {
gotPltHeaderEntriesNum = 2;
defaultMaxPageSize = 65536;
Expand Down
2 changes: 2 additions & 0 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,8 @@ struct Ctx : CommonLinkerContext {
std::unique_ptr<llvm::TarWriter> tar;
// InputFile for linker created symbols with no source location.
InputFile *internalFile = nullptr;
// Dummy Undefined for relocations without a symbol.
Undefined *dummySym = nullptr;
// True if symbols can be exported (isExported) or preemptible.
bool hasDynsym = false;
// True if SHT_LLVM_SYMPART is used.
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3138,6 +3138,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
ctx.symtab->insert(arg->getValue())->traced = true;

ctx.internalFile = createInternalFile(ctx, "<internal>");
ctx.dummySym = make<Undefined>(ctx.internalFile, "", STB_LOCAL, 0, 0);

// Handle -u/--undefined before input files. If both a.a and b.so define foo,
// -u foo a.a b.so will extract a.a.
Expand Down
5 changes: 5 additions & 0 deletions lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,11 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
return ctx.in.mipsGot->getVA() +
ctx.in.mipsGot->getPageEntryOffset(file, *r.sym, a) -
ctx.in.mipsGot->getGp(file);
case RE_MIPS_OSEC_LOCAL_PAGE:
// This is used by the MIPS multi-GOT implementation. It relocates
// addresses of 64kb pages that lie inside the output section that sym is
// a representative for.
return getMipsPageAddr(r.sym->getOutputSection()->addr) + a;
case RE_MIPS_GOT_OFF:
case RE_MIPS_GOT_OFF32:
// In case of MIPS if a GOT relocation has non-zero addend this addend
Expand Down
29 changes: 13 additions & 16 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -885,10 +885,12 @@ static void addPltEntry(Ctx &ctx, PltSection &plt, GotPltSection &gotPlt,
RelocationBaseSection &rel, RelType type, Symbol &sym) {
plt.addEntry(sym);
gotPlt.addEntry(sym);
rel.addReloc({type, &gotPlt, sym.getGotPltOffset(ctx),
sym.isPreemptible ? DynamicReloc::AgainstSymbol
: DynamicReloc::AddendOnlyWithTargetVA,
sym, 0, R_ABS});
if (sym.isPreemptible)
rel.addReloc(
{type, &gotPlt, sym.getGotPltOffset(ctx), true, sym, 0, R_ADDEND});
else
rel.addReloc(
{type, &gotPlt, sym.getGotPltOffset(ctx), false, sym, 0, R_ABS});
}

void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
Expand All @@ -897,9 +899,8 @@ void elf::addGotEntry(Ctx &ctx, Symbol &sym) {

// If preemptible, emit a GLOB_DAT relocation.
if (sym.isPreemptible) {
ctx.mainPart->relaDyn->addReloc({ctx.target->gotRel, ctx.in.got.get(), off,
DynamicReloc::AgainstSymbol, sym, 0,
R_ABS});
ctx.mainPart->relaDyn->addReloc(
{ctx.target->gotRel, ctx.in.got.get(), off, true, sym, 0, R_ADDEND});
return;
}

Expand All @@ -920,15 +921,13 @@ static void addGotAuthEntry(Ctx &ctx, Symbol &sym) {
// If preemptible, emit a GLOB_DAT relocation.
if (sym.isPreemptible) {
ctx.mainPart->relaDyn->addReloc({R_AARCH64_AUTH_GLOB_DAT, ctx.in.got.get(),
off, DynamicReloc::AgainstSymbol, sym, 0,
R_ABS});
off, true, sym, 0, R_ADDEND});
return;
}

// Signed GOT requires dynamic relocation.
ctx.in.got->getPartition(ctx).relaDyn->addReloc(
{R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off,
DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS});
{R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off, false, sym, 0, R_ABS});
}

static void addTpOffsetGotEntry(Ctx &ctx, Symbol &sym) {
Expand Down Expand Up @@ -1159,9 +1158,8 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
sec->addReloc({expr, type, offset, addend, &sym});
part.relrAuthDyn->relocs.push_back({sec, sec->relocs().size() - 1});
} else {
part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, sec, offset,
DynamicReloc::AddendOnlyWithTargetVA, sym,
addend, R_ABS});
part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, sec, offset, false,
sym, addend, R_ABS});
}
return;
}
Expand Down Expand Up @@ -1948,13 +1946,12 @@ void elf::postScanRelocations(Ctx &ctx) {

GotSection *got = ctx.in.got.get();
if (ctx.needsTlsLd.load(std::memory_order_relaxed) && got->addTlsIndex()) {
static Undefined dummy(ctx.internalFile, "", STB_LOCAL, 0, 0);
if (ctx.arg.shared)
ctx.mainPart->relaDyn->addReloc(
{ctx.target->tlsModuleIndexRel, got, got->getTlsIndexOff()});
else
got->addConstant({R_ADDEND, ctx.target->symbolicRel,
got->getTlsIndexOff(), 1, &dummy});
got->getTlsIndexOff(), 1, ctx.dummySym});
}

assert(ctx.symAux.size() == 1);
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/Relocations.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ enum RelExpr {
RE_MIPS_GOT_LOCAL_PAGE,
RE_MIPS_GOT_OFF,
RE_MIPS_GOT_OFF32,
RE_MIPS_OSEC_LOCAL_PAGE,
RE_MIPS_TLSGD,
RE_MIPS_TLSLD,
RE_PPC32_PLTREL,
Expand Down
56 changes: 18 additions & 38 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -769,10 +769,6 @@ void GotSection::writeTo(uint8_t *buf) {
}
}

static uint64_t getMipsPageAddr(uint64_t addr) {
return (addr + 0x8000) & ~0xffff;
}

static uint64_t getMipsPageCount(uint64_t size) {
return (size + 0xfffe) / 0xffff + 1;
}
Expand All @@ -786,7 +782,7 @@ void MipsGotSection::addEntry(InputFile &file, Symbol &sym, int64_t addend,
FileGot &g = getGot(file);
if (expr == RE_MIPS_GOT_LOCAL_PAGE) {
if (const OutputSection *os = sym.getOutputSection())
g.pagesMap.insert({os, {}});
g.pagesMap.insert({os, {&sym}});
else
g.local16.insert({{nullptr, getMipsPageAddr(sym.getVA(ctx, addend))}, 0});
} else if (sym.isTls())
Expand Down Expand Up @@ -1066,8 +1062,7 @@ void MipsGotSection::build() {
// be allocated before us in the static TLS block.
if (s->isPreemptible || ctx.arg.shared)
ctx.mainPart->relaDyn->addReloc(
{ctx.target->tlsGotRel, this, offset,
DynamicReloc::AgainstSymbolWithTargetVA, *s, 0, R_ABS});
{ctx.target->tlsGotRel, this, offset, true, *s, 0, R_ABS});
}
for (std::pair<Symbol *, size_t> &p : got.dynTlsSymbols) {
Symbol *s = p.first;
Expand Down Expand Up @@ -1115,15 +1110,16 @@ void MipsGotSection::build() {
size_t pageCount = l.second.count;
for (size_t pi = 0; pi < pageCount; ++pi) {
uint64_t offset = (l.second.firstIndex + pi) * ctx.arg.wordsize;
ctx.mainPart->relaDyn->addReloc({ctx.target->relativeRel, this, offset,
l.first, int64_t(pi * 0x10000)});
ctx.mainPart->relaDyn->addReloc(
{ctx.target->relativeRel, this, offset, false, *l.second.repSym,
int64_t(pi * 0x10000), RE_MIPS_OSEC_LOCAL_PAGE});
}
}
for (const std::pair<GotEntry, size_t> &p : got.local16) {
uint64_t offset = p.second * ctx.arg.wordsize;
ctx.mainPart->relaDyn->addReloc({ctx.target->relativeRel, this, offset,
DynamicReloc::AddendOnlyWithTargetVA,
*p.first.first, p.first.second, R_ABS});
false, *p.first.first, p.first.second,
R_ABS});
}
}
}
Expand Down Expand Up @@ -1646,24 +1642,10 @@ uint64_t DynamicReloc::getOffset() const {
}

int64_t DynamicReloc::computeAddend(Ctx &ctx) const {
switch (kind) {
case AddendOnly:
assert(sym == nullptr);
return addend;
case AgainstSymbol:
assert(sym != nullptr);
return addend;
case AddendOnlyWithTargetVA:
case AgainstSymbolWithTargetVA: {
uint64_t ca = inputSec->getRelocTargetVA(
ctx, Relocation{expr, type, 0, addend, sym}, getOffset());
return ctx.arg.is64 ? ca : SignExtend64<32>(ca);
}
case MipsMultiGotPage:
assert(sym == nullptr);
return getMipsPageAddr(outputSec->addr) + addend;
}
llvm_unreachable("Unknown DynamicReloc::Kind enum");
assert(!isFinal && "addend already computed");
uint64_t ca = inputSec->getRelocTargetVA(
ctx, Relocation{expr, type, 0, addend, sym}, getOffset());
return ctx.arg.is64 ? ca : SignExtend64<32>(ca);
}

uint32_t DynamicReloc::getSymIndex(SymbolTableBaseSection *symTab) const {
Expand Down Expand Up @@ -1691,20 +1673,18 @@ RelocationBaseSection::RelocationBaseSection(Ctx &ctx, StringRef name,
void RelocationBaseSection::addSymbolReloc(
RelType dynType, InputSectionBase &isec, uint64_t offsetInSec, Symbol &sym,
int64_t addend, std::optional<RelType> addendRelType) {
addReloc(DynamicReloc::AgainstSymbol, dynType, isec, offsetInSec, sym, addend,
R_ADDEND, addendRelType ? *addendRelType : ctx.target->noneRel);
addReloc(true, dynType, isec, offsetInSec, sym, addend, R_ADDEND,
addendRelType ? *addendRelType : ctx.target->noneRel);
}

void RelocationBaseSection::addAddendOnlyRelocIfNonPreemptible(
RelType dynType, InputSectionBase &isec, uint64_t offsetInSec, Symbol &sym,
RelType addendRelType) {
// No need to write an addend to the section for preemptible symbols.
if (sym.isPreemptible)
addReloc({dynType, &isec, offsetInSec, DynamicReloc::AgainstSymbol, sym, 0,
R_ABS});
addReloc({dynType, &isec, offsetInSec, true, sym, 0, R_ADDEND});
else
addReloc(DynamicReloc::AddendOnlyWithTargetVA, dynType, isec, offsetInSec,
sym, 0, R_ABS, addendRelType);
addReloc(false, dynType, isec, offsetInSec, sym, 0, R_ABS, addendRelType);
}

void RelocationBaseSection::mergeRels() {
Expand Down Expand Up @@ -1744,17 +1724,17 @@ void RelocationBaseSection::finalizeContents() {
}
}

void DynamicReloc::computeRaw(Ctx &ctx, SymbolTableBaseSection *symt) {
void DynamicReloc::finalize(Ctx &ctx, SymbolTableBaseSection *symt) {
r_offset = getOffset();
r_sym = getSymIndex(symt);
addend = computeAddend(ctx);
kind = AddendOnly; // Catch errors
isFinal = true; // Catch errors
}

void RelocationBaseSection::computeRels() {
SymbolTableBaseSection *symTab = getPartition(ctx).dynSymTab.get();
parallelForEach(relocs, [&ctx = ctx, symTab](DynamicReloc &rel) {
rel.computeRaw(ctx, symTab);
rel.finalize(ctx, symTab);
});

auto irelative = std::stable_partition(
Expand Down
71 changes: 26 additions & 45 deletions lld/ELF/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,9 +327,11 @@ class MipsGotSection final : public SyntheticSection {
size_t startIndex = 0;

struct PageBlock {
Symbol *repSym; // Representative symbol for the OutputSection
size_t firstIndex;
size_t count;
PageBlock() : firstIndex(0), count(0) {}
PageBlock(Symbol *repSym = nullptr)
: repSym(repSym), firstIndex(0), count(0) {}
};

// Map output sections referenced by MIPS GOT relocations
Expand Down Expand Up @@ -418,61 +420,31 @@ class StringTableSection final : public SyntheticSection {

class DynamicReloc {
public:
enum Kind {
/// The resulting dynamic relocation does not reference a symbol (#sym must
/// be nullptr) and uses #addend as the result of computeAddend(ctx).
AddendOnly,
/// The resulting dynamic relocation will not reference a symbol: #sym is
/// only used to compute the addend with InputSection::getRelocTargetVA().
/// Useful for various relative and TLS relocations (e.g. R_X86_64_TPOFF64).
AddendOnlyWithTargetVA,
/// The resulting dynamic relocation references symbol #sym from the dynamic
/// symbol table and uses #addend as the value of computeAddend(ctx).
AgainstSymbol,
/// The resulting dynamic relocation references symbol #sym from the dynamic
/// symbol table and uses InputSection::getRelocTargetVA() + #addend for the
/// final addend. It can be used for relocations that write the symbol VA as
// the addend (e.g. R_MIPS_TLS_TPREL64) but still reference the symbol.
AgainstSymbolWithTargetVA,
/// This is used by the MIPS multi-GOT implementation. It relocates
/// addresses of 64kb pages that lie inside the output section.
MipsMultiGotPage,
};
/// This constructor records a relocation against a symbol.
/// This constructor records a normal relocation.
DynamicReloc(RelType type, const InputSectionBase *inputSec,
uint64_t offsetInSec, Kind kind, Symbol &sym, int64_t addend,
RelExpr expr)
uint64_t offsetInSec, bool isAgainstSymbol, Symbol &sym,
int64_t addend, RelExpr expr)
: sym(&sym), inputSec(inputSec), offsetInSec(offsetInSec), type(type),
addend(addend), kind(kind), expr(expr) {}
addend(addend), isAgainstSymbol(isAgainstSymbol), isFinal(false),
expr(expr) {}
/// This constructor records a relative relocation with no symbol.
DynamicReloc(RelType type, const InputSectionBase *inputSec,
uint64_t offsetInSec, int64_t addend = 0)
: sym(nullptr), inputSec(inputSec), offsetInSec(offsetInSec), type(type),
addend(addend), kind(AddendOnly), expr(R_ADDEND) {}
/// This constructor records dynamic relocation settings used by the MIPS
/// multi-GOT implementation.
DynamicReloc(RelType type, const InputSectionBase *inputSec,
uint64_t offsetInSec, const OutputSection *outputSec,
int64_t addend)
: sym(nullptr), outputSec(outputSec), inputSec(inputSec),
offsetInSec(offsetInSec), type(type), addend(addend),
kind(MipsMultiGotPage), expr(R_ADDEND) {}
: DynamicReloc(type, inputSec, offsetInSec, false,
*inputSec->getCtx().dummySym, addend, R_ADDEND) {}

uint64_t getOffset() const;
uint32_t getSymIndex(SymbolTableBaseSection *symTab) const;
bool needsDynSymIndex() const {
return kind == AgainstSymbol || kind == AgainstSymbolWithTargetVA;
}
bool needsDynSymIndex() const { return isAgainstSymbol; }

/// Computes the addend of the dynamic relocation. Note that this is not the
/// same as the #addend member variable as it may also include the symbol
/// address/the address of the corresponding GOT entry/etc.
int64_t computeAddend(Ctx &) const;

void computeRaw(Ctx &, SymbolTableBaseSection *symt);
void finalize(Ctx &, SymbolTableBaseSection *symt);

Symbol *sym;
const OutputSection *outputSec = nullptr;
const InputSectionBase *inputSec;
uint64_t offsetInSec;
uint64_t r_offset;
Expand All @@ -483,7 +455,15 @@ class DynamicReloc {
int64_t addend;

private:
Kind kind;
/// Whether this was constructed with a Kind of AgainstSymbol.
LLVM_PREFERRED_TYPE(bool)
uint8_t isAgainstSymbol : 1;

/// The resulting dynamic relocation has already had its addend computed.
/// Calling computeAddend() is an error.
LLVM_PREFERRED_TYPE(bool)
uint8_t isFinal : 1;

// The kind of expression used to calculate the added (required e.g. for
// relative GOT relocations).
RelExpr expr;
Expand Down Expand Up @@ -528,8 +508,8 @@ class RelocationBaseSection : public SyntheticSection {
uint64_t offsetInSec, Symbol &sym, int64_t addend,
RelType addendRelType, RelExpr expr) {
assert(expr != R_ADDEND && "expected non-addend relocation expression");
addReloc<shard>(DynamicReloc::AddendOnlyWithTargetVA, dynType, isec,
offsetInSec, sym, addend, expr, addendRelType);
addReloc<shard>(false, dynType, isec, offsetInSec, sym, addend, expr,
addendRelType);
}
/// Add a dynamic relocation using the target address of \p sym as the addend
/// if \p sym is non-preemptible. Otherwise add a relocation against \p sym.
Expand All @@ -538,14 +518,15 @@ class RelocationBaseSection : public SyntheticSection {
uint64_t offsetInSec, Symbol &sym,
RelType addendRelType);
template <bool shard = false>
void addReloc(DynamicReloc::Kind kind, RelType dynType, InputSectionBase &sec,
void addReloc(bool isAgainstSymbol, RelType dynType, InputSectionBase &sec,
uint64_t offsetInSec, Symbol &sym, int64_t addend, RelExpr expr,
RelType addendRelType) {
// Write the addends to the relocated address if required. We skip
// it if the written value would be zero.
if (ctx.arg.writeAddends && (expr != R_ADDEND || addend != 0))
sec.addReloc({expr, addendRelType, offsetInSec, addend, &sym});
addReloc<shard>({dynType, &sec, offsetInSec, kind, sym, addend, expr});
addReloc<shard>(
{dynType, &sec, offsetInSec, isAgainstSymbol, sym, addend, expr});
}
bool isNeeded() const override {
return !relocs.empty() ||
Expand Down
3 changes: 1 addition & 2 deletions lld/ELF/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,9 @@ ErrorPlace elf::getErrorPlace(Ctx &ctx, const uint8_t *loc) {
if (isecLoc <= loc && loc < isecLoc + isec->getSize()) {
std::string objLoc = isec->getLocation(loc - isecLoc);
// Return object file location and source file location.
Undefined dummy(ctx.internalFile, "", STB_LOCAL, 0, 0);
ELFSyncStream msg(ctx, DiagLevel::None);
if (isec->file)
msg << isec->getSrcMsg(dummy, loc - isecLoc);
msg << isec->getSrcMsg(*ctx.dummySym, loc - isecLoc);
return {isec, objLoc + ": ", std::string(msg.str())};
}
}
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ void processArmCmseSymbols(Ctx &);
template <class ELFT> uint32_t calcMipsEFlags(Ctx &);
uint8_t getMipsFpAbiFlag(Ctx &, InputFile *file, uint8_t oldFlag,
uint8_t newFlag);
uint64_t getMipsPageAddr(uint64_t addr);
bool isMipsN32Abi(Ctx &, const InputFile &f);
bool isMicroMips(Ctx &);
bool isMipsR6(Ctx &);
Expand Down
Loading
Loading