diff options
Diffstat (limited to 'lld/ELF')
-rw-r--r-- | lld/ELF/Arch/LoongArch.cpp | 9 | ||||
-rw-r--r-- | lld/ELF/Arch/Mips.cpp | 4 | ||||
-rw-r--r-- | lld/ELF/Config.h | 2 | ||||
-rw-r--r-- | lld/ELF/Driver.cpp | 1 | ||||
-rw-r--r-- | lld/ELF/InputSection.cpp | 5 | ||||
-rw-r--r-- | lld/ELF/Relocations.cpp | 29 | ||||
-rw-r--r-- | lld/ELF/Relocations.h | 1 | ||||
-rw-r--r-- | lld/ELF/SyntheticSections.cpp | 56 | ||||
-rw-r--r-- | lld/ELF/SyntheticSections.h | 71 | ||||
-rw-r--r-- | lld/ELF/Target.cpp | 3 | ||||
-rw-r--r-- | lld/ELF/Target.h | 1 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 5 |
12 files changed, 80 insertions, 107 deletions
diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp index 15dcddb..a145530 100644 --- a/lld/ELF/Arch/LoongArch.cpp +++ b/lld/ELF/Arch/LoongArch.cpp @@ -809,10 +809,13 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i, // address. // Meanwhile skip undefined, preemptible and STT_GNU_IFUNC symbols, because // these symbols may be resolve in runtime. + // Moreover, relaxation can only occur if the addends of both relocations are + // zero for GOT references. if (rHi20.type == R_LARCH_GOT_PC_HI20 && - (!rHi20.sym->isDefined() || rHi20.sym->isPreemptible || - rHi20.sym->isGnuIFunc() || - (ctx.arg.isPic && !cast<Defined>(*rHi20.sym).section))) + (!rHi20.sym || rHi20.sym != rLo12.sym || !rHi20.sym->isDefined() || + rHi20.sym->isPreemptible || rHi20.sym->isGnuIFunc() || + (ctx.arg.isPic && !cast<Defined>(*rHi20.sym).section) || + rHi20.addend != 0 || rLo12.addend != 0)) return; uint64_t dest = 0; diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp index 91c7f15..f88b021c 100644 --- a/lld/ELF/Arch/Mips.cpp +++ b/lld/ELF/Arch/Mips.cpp @@ -40,6 +40,10 @@ public: }; } // 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; diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index e7622dd..a83a4c1 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -702,6 +702,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. diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 91e11bc..6c2f318 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -3140,6 +3140,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. diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 68e3feb..784ff7c 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -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 diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index bd22fe2..32ac28d6 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -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) { @@ -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; } @@ -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) { @@ -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; } @@ -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); diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index 02ddf70..c1c4860 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -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, diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index efec41a..0d87f9a 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -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; } @@ -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()) @@ -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; @@ -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}); } } } @@ -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 { @@ -1691,8 +1673,8 @@ 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( @@ -1700,11 +1682,9 @@ void RelocationBaseSection::addAddendOnlyRelocIfNonPreemptible( 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() { @@ -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( diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 5f01513..223dfe3 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -327,9 +327,11 @@ private: 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 @@ -418,61 +420,31 @@ private: 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; @@ -483,7 +455,15 @@ public: 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; @@ -528,8 +508,8 @@ public: 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. @@ -538,14 +518,15 @@ public: 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() || diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index ad7d57d..4946484 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -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())}; } } diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index f4a6d83..fdc0c20 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -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 &); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index c3c0578..2b0e097 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1586,9 +1586,8 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() { if (isInt<32>(reloc.sym->getVA(ctx, reloc.addend))) return false; part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, elem.inputSec, - reloc.offset, - DynamicReloc::AddendOnlyWithTargetVA, - *reloc.sym, reloc.addend, R_ABS}); + reloc.offset, false, *reloc.sym, + reloc.addend, R_ABS}); return true; }); changed |= (it != part.relrAuthDyn->relocs.end()); |