diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp index f88b021c8ba39..78e8cc3e3cc11 100644 --- a/lld/ELF/Arch/Mips.cpp +++ b/lld/ELF/Arch/Mips.cpp @@ -593,6 +593,7 @@ void MIPS::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: @@ -601,6 +602,7 @@ void MIPS::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: diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 0f91c25da2d56..08f8f656eff6e 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -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); @@ -1051,16 +1055,22 @@ 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 &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); } @@ -1068,58 +1078,81 @@ void MipsGotSection::build() { 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 &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 &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 &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 &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); } } } @@ -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 &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 &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 &p : g.global) - write(p.second, p.first, 0); - for (const std::pair &p : g.relocs) - write(p.second, p.first, 0); - for (const std::pair &p : g.tls) { - if (!p.first->isPreemptible && !ctx.arg.shared) - write(p.second, p.first, -0x7000); - } - for (const std::pair &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 diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 223dfe3b67b10..38f2ed421b6fd 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -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);