Skip to content

[NFCI][ELF][Mips] Refactor MipsGotSection to avoid explicit writes #150730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: users/jrtc27/spr/main.nfcielfmips-refactor-mipsgotsection-to-avoid-explicit-writes
Choose a base branch
from
Open
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions lld/ELF/Arch/Mips.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ void MIPS<ELFT>::relocate(uint8_t *loc, const Relocation &rel,

switch (type) {
case R_MIPS_32:
case R_MIPS_REL32:
case R_MIPS_GPREL32:
case R_MIPS_TLS_DTPREL32:
case R_MIPS_TLS_TPREL32:
Expand All @@ -601,6 +602,7 @@ void MIPS<ELFT>::relocate(uint8_t *loc, const Relocation &rel,
case R_MIPS_64:
case R_MIPS_TLS_DTPREL64:
case R_MIPS_TLS_TPREL64:
case (R_MIPS_64 << 8) | R_MIPS_REL32:
write64(ctx, loc, val);
break;
case R_MIPS_26:
Expand Down
143 changes: 65 additions & 78 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,10 @@ MipsGotSection::MipsGotSection(Ctx &ctx)
: SyntheticSection(ctx, ".got", SHT_PROGBITS,
SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, 16) {}

void MipsGotSection::addConstant(const Relocation &r) {
relocations.push_back(r);
}

void MipsGotSection::addEntry(InputFile &file, Symbol &sym, int64_t addend,
RelExpr expr) {
FileGot &g = getGot(file);
Expand Down Expand Up @@ -1051,75 +1055,104 @@ void MipsGotSection::build() {
ctx.symAux.back().gotIdx = p.second;
}

// Create dynamic relocations.
// Create relocations.
//
// Note the primary GOT's local and global relocations are implicit, and the
// MIPS ABI requires the VA be written even for the global entries, so we
// treat both as constants here.
for (FileGot &got : gots) {
// Create dynamic relocations for TLS entries.
// Create relocations for TLS entries.
for (std::pair<Symbol *, size_t> &p : got.tls) {
Symbol *s = p.first;
uint64_t offset = p.second * ctx.arg.wordsize;
// When building a shared library we still need a dynamic relocation
// for the TP-relative offset as we don't know how much other data will
// be allocated before us in the static TLS block.
if (s->isPreemptible || ctx.arg.shared)
if (!s->isPreemptible && !ctx.arg.shared)
addConstant({R_TPREL, ctx.target->symbolicRel, offset, 0, s});
else
ctx.mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
ctx.target->tlsGotRel, *this, offset, *s, ctx.target->symbolicRel);
}
for (std::pair<Symbol *, size_t> &p : got.dynTlsSymbols) {
Symbol *s = p.first;
uint64_t offset = p.second * ctx.arg.wordsize;
if (s == nullptr) {
if (!ctx.arg.shared)
continue;
ctx.mainPart->relaDyn->addReloc(
{ctx.target->tlsModuleIndexRel, this, offset});
if (ctx.arg.shared)
ctx.mainPart->relaDyn->addReloc(
{ctx.target->tlsModuleIndexRel, this, offset});
else
addConstant(
{R_ADDEND, ctx.target->symbolicRel, offset, 1, ctx.dummySym});
} else {
// When building a shared library we still need a dynamic relocation
// for the module index. Therefore only checking for
// S->isPreemptible is not sufficient (this happens e.g. for
// thread-locals that have been marked as local through a linker script)
if (!s->isPreemptible && !ctx.arg.shared)
continue;
ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->tlsModuleIndexRel,
*this, offset, *s);
// Write one to the GOT slot.
addConstant({R_ADDEND, ctx.target->symbolicRel, offset, 1, s});
else
ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->tlsModuleIndexRel,
*this, offset, *s);
offset += ctx.arg.wordsize;
// However, we can skip writing the TLS offset reloc for non-preemptible
// symbols since it is known even in shared libraries
if (!s->isPreemptible)
continue;
offset += ctx.arg.wordsize;
ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->tlsOffsetRel, *this,
offset, *s);
if (s->isPreemptible)
ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->tlsOffsetRel, *this,
offset, *s);
else
addConstant({R_ABS, ctx.target->tlsOffsetRel, offset, 0, s});
}
}

// Do not create dynamic relocations for non-TLS
// entries in the primary GOT.
if (&got == primGot)
continue;

// Dynamic relocations for "global" entries.
// Relocations for "global" entries.
for (const std::pair<Symbol *, size_t> &p : got.global) {
uint64_t offset = p.second * ctx.arg.wordsize;
ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->relativeRel, *this,
offset, *p.first);
if (&got == primGot)
addConstant({R_ABS, ctx.target->relativeRel, offset, 0, p.first});
else
ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->relativeRel, *this,
offset, *p.first);
}
if (!ctx.arg.isPic)
continue;
// Dynamic relocations for "local" entries in case of PIC.
// Relocation-only entries exist as dummy entries for dynamic symbols that
// aren't otherwise in the primary GOT, as the ABI requires an entry for
// each dynamic symbol. Secondary GOTs have no need for them.
assert((got.relocs.empty() || &got == primGot) &&
"Relocation-only entries should only be in the primary GOT");
for (const std::pair<Symbol *, size_t> &p : got.relocs) {
uint64_t offset = p.second * ctx.arg.wordsize;
addConstant({R_ABS, ctx.target->relativeRel, offset, 0, p.first});
}

// Relocations for "local" entries
for (const std::pair<const OutputSection *, FileGot::PageBlock> &l :
got.pagesMap) {
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, false, *l.second.repSym,
int64_t(pi * 0x10000), RE_MIPS_OSEC_LOCAL_PAGE});
int64_t addend = int64_t(pi * 0x10000);
if (!ctx.arg.isPic || &got == primGot)
addConstant({RE_MIPS_OSEC_LOCAL_PAGE, ctx.target->relativeRel, offset,
addend, l.second.repSym});
else
ctx.mainPart->relaDyn->addRelativeReloc(
ctx.target->relativeRel, *this, offset, *l.second.repSym, addend,
ctx.target->relativeRel, 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,
false, *p.first.first, p.first.second,
R_ABS});
if (p.first.first == nullptr)
addConstant({R_ADDEND, ctx.target->relativeRel, offset, p.first.second,
ctx.dummySym});
else if (!ctx.arg.isPic || &got == primGot)
addConstant({R_ABS, ctx.target->relativeRel, offset, p.first.second,
p.first.first});
else
ctx.mainPart->relaDyn->addRelativeReloc(
ctx.target->relativeRel, *this, offset, *p.first.first,
p.first.second, ctx.target->relativeRel, R_ABS);
}
}
}
Expand Down Expand Up @@ -1157,52 +1190,6 @@ void MipsGotSection::writeTo(uint8_t *buf) {
writeUint(ctx, buf + ctx.arg.wordsize,
(uint64_t)1 << (ctx.arg.wordsize * 8 - 1));
ctx.target->relocateAlloc(*this, buf);
for (const FileGot &g : gots) {
auto write = [&](size_t i, const Symbol *s, int64_t a) {
uint64_t va = a;
if (s)
va = s->getVA(ctx, a);
writeUint(ctx, buf + i * ctx.arg.wordsize, va);
};
// Write 'page address' entries to the local part of the GOT.
for (const std::pair<const OutputSection *, FileGot::PageBlock> &l :
g.pagesMap) {
size_t pageCount = l.second.count;
uint64_t firstPageAddr = getMipsPageAddr(l.first->addr);
for (size_t pi = 0; pi < pageCount; ++pi)
write(l.second.firstIndex + pi, nullptr, firstPageAddr + pi * 0x10000);
}
// Local, global, TLS, reloc-only entries.
// If TLS entry has a corresponding dynamic relocations, leave it
// initialized by zero. Write down adjusted TLS symbol's values otherwise.
// To calculate the adjustments use offsets for thread-local storage.
// http://web.archive.org/web/20190324223224/https://www.linux-mips.org/wiki/NPTL
for (const std::pair<GotEntry, size_t> &p : g.local16)
write(p.second, p.first.first, p.first.second);
// Write VA to the primary GOT only. For secondary GOTs that
// will be done by REL32 dynamic relocations.
if (&g == &gots.front())
for (const std::pair<Symbol *, size_t> &p : g.global)
write(p.second, p.first, 0);
for (const std::pair<Symbol *, size_t> &p : g.relocs)
write(p.second, p.first, 0);
for (const std::pair<Symbol *, size_t> &p : g.tls) {
if (!p.first->isPreemptible && !ctx.arg.shared)
write(p.second, p.first, -0x7000);
}
for (const std::pair<Symbol *, size_t> &p : g.dynTlsSymbols) {
if (p.first == nullptr && !ctx.arg.shared)
write(p.second, nullptr, 1);
else if (p.first && !p.first->isPreemptible) {
// If we are emitting a shared library with relocations we mustn't write
// anything to the GOT here. When using Elf_Rel relocations the value
// one will be treated as an addend and will cause crashes at runtime
if (!ctx.arg.shared)
write(p.second, nullptr, 1);
write(p.second + 1, p.first, -0x8000);
}
}
}
}

// On PowerPC the .plt section is used to hold the table of function addresses
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ class MipsGotSection final : public SyntheticSection {
// primary and optional multiple secondary GOTs.
void build();

void addConstant(const Relocation &r);
void addEntry(InputFile &file, Symbol &sym, int64_t addend, RelExpr expr);
void addDynTlsEntry(InputFile &file, Symbol &sym);
void addTlsIndex(InputFile &file);
Expand Down
Loading