diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -64,8 +64,9 @@ symbolicRel = R_AARCH64_ABS64; tlsDescRel = R_AARCH64_TLSDESC; tlsGotRel = R_AARCH64_TLS_TPREL64; - pltEntrySize = 16; pltHeaderSize = 32; + pltEntrySize = 16; + ipltEntrySize = 16; defaultMaxPageSize = 65536; // Align to the 2 MiB page size (known as a superpage or huge page). @@ -590,8 +591,10 @@ btiEntry = btiHeader && !config->shared; pacEntry = (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_PAC); - if (btiEntry || pacEntry) + if (btiEntry || pacEntry) { pltEntrySize = 24; + ipltEntrySize = 24; + } } void AArch64BtiPac::writePltHeader(uint8_t *buf) const { diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp --- a/lld/ELF/Arch/ARM.cpp +++ b/lld/ELF/Arch/ARM.cpp @@ -59,8 +59,9 @@ tlsModuleIndexRel = R_ARM_TLS_DTPMOD32; tlsOffsetRel = R_ARM_TLS_DTPOFF32; gotBaseSymInGotPlt = false; - pltEntrySize = 16; pltHeaderSize = 32; + pltEntrySize = 16; + ipltEntrySize = 16; trapInstr = {0xd4, 0xd4, 0xd4, 0xd4}; needsThunks = true; } diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp --- a/lld/ELF/Arch/PPC.cpp +++ b/lld/ELF/Arch/PPC.cpp @@ -144,6 +144,7 @@ gotPltHeaderEntriesNum = 0; pltHeaderSize = 64; // size of PLTresolve in .glink pltEntrySize = 4; + ipltEntrySize = 4; needsThunks = true; diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -296,11 +296,12 @@ relativeRel = R_PPC64_RELATIVE; iRelativeRel = R_PPC64_IRELATIVE; symbolicRel = R_PPC64_ADDR64; + pltHeaderSize = 60; pltEntrySize = 4; + ipltEntrySize = 4; gotBaseSymInGotPlt = false; gotHeaderEntriesNum = 1; gotPltHeaderEntriesNum = 2; - pltHeaderSize = 60; needsThunks = true; tlsModuleIndexRel = R_PPC64_DTPMOD64; diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp --- a/lld/ELF/Arch/RISCV.cpp +++ b/lld/ELF/Arch/RISCV.cpp @@ -95,8 +95,9 @@ // .got.plt[0] = _dl_runtime_resolve, .got.plt[1] = link_map gotPltHeaderEntriesNum = 2; - pltEntrySize = 16; pltHeaderSize = 32; + pltEntrySize = 16; + ipltEntrySize = 16; } static uint32_t getEFlags(InputFile *f) { diff --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp --- a/lld/ELF/Arch/X86.cpp +++ b/lld/ELF/Arch/X86.cpp @@ -57,8 +57,9 @@ tlsGotRel = R_386_TLS_TPOFF; tlsModuleIndexRel = R_386_TLS_DTPMOD32; tlsOffsetRel = R_386_TLS_DTPOFF32; - pltEntrySize = 16; pltHeaderSize = 16; + pltEntrySize = 16; + ipltEntrySize = 16; trapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 // Align to the non-PAE large page size (known as a superpage or huge page). @@ -432,6 +433,7 @@ RetpolinePic::RetpolinePic() { pltHeaderSize = 48; pltEntrySize = 32; + ipltEntrySize = 32; } void RetpolinePic::writeGotPlt(uint8_t *buf, const Symbol &s) const { @@ -485,6 +487,7 @@ RetpolineNoPic::RetpolineNoPic() { pltHeaderSize = 48; pltEntrySize = 32; + ipltEntrySize = 32; } void RetpolineNoPic::writeGotPlt(uint8_t *buf, const Symbol &s) const { diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp --- a/lld/ELF/Arch/X86_64.cpp +++ b/lld/ELF/Arch/X86_64.cpp @@ -61,8 +61,9 @@ tlsGotRel = R_X86_64_TPOFF64; tlsModuleIndexRel = R_X86_64_DTPMOD64; tlsOffsetRel = R_X86_64_DTPOFF64; - pltEntrySize = 16; pltHeaderSize = 16; + pltEntrySize = 16; + ipltEntrySize = 16; trapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 // Align to the large page size (known as a superpage or huge page). @@ -599,6 +600,7 @@ Retpoline::Retpoline() { pltHeaderSize = 48; pltEntrySize = 32; + ipltEntrySize = 32; } void Retpoline::writeGotPlt(uint8_t *buf, const Symbol &s) const { @@ -639,7 +641,7 @@ }; memcpy(buf, insn, sizeof(insn)); - uint64_t off = pltHeaderSize + pltEntrySize * index; + uint64_t off = pltEntryAddr - in.plt->getVA(); write32le(buf + 3, gotPltEntryAddr - pltEntryAddr - 7); write32le(buf + 8, -off - 12 + 32); @@ -651,6 +653,7 @@ RetpolineZNow::RetpolineZNow() { pltHeaderSize = 32; pltEntrySize = 16; + ipltEntrySize = 16; } void RetpolineZNow::writePltHeader(uint8_t *buf) const { diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1011,10 +1011,10 @@ expr, type); } -template +template static void addPltEntry(PltSection *plt, GotPltSection *gotPlt, RelocationBaseSection *rel, RelType type, Symbol &sym) { - plt->addEntry(sym); + plt->template addEntry(sym); gotPlt->addEntry(sym); rel->addReloc( {type, gotPlt, sym.getGotPltOffset(), !sym.isPreemptible, &sym, 0}); @@ -1415,13 +1415,9 @@ } else if (!needsPlt(expr)) { // Make the ifunc's PLT entry canonical by changing the value of its // symbol to redirect all references to point to it. - unsigned entryOffset = sym.pltIndex * target->pltEntrySize; - if (config->zRetpolineplt) - entryOffset += target->pltHeaderSize; - auto &d = cast(sym); d.section = in.iplt; - d.value = entryOffset; + d.value = sym.pltIndex * target->pltEntrySize; d.size = 0; // It's important to set the symbol type here so that dynamic loaders // don't try to call the PLT as if it were an ifunc resolver. diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -163,9 +163,11 @@ } uint64_t Symbol::getPltVA() const { - PltSection *plt = isInIplt ? in.iplt : in.plt; - uint64_t outVA = - plt->getVA() + plt->headerSize + pltIndex * target->pltEntrySize; + uint64_t outVA = isInIplt + ? in.iplt->getVA() + pltIndex * target->ipltEntrySize + : in.plt->getVA() + in.plt->headerSize + + pltIndex * target->pltEntrySize; + // While linking microMIPS code PLT code are always microMIPS // code. Set the less-significant bit to track that fact. // See detailed comment in the `getSymVA` function. diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -668,10 +668,10 @@ // Target->IRelativeRel. class PltSection : public SyntheticSection { public: - PltSection(bool isIplt); + PltSection(); void writeTo(uint8_t *buf) override; size_t getSize() const override; - bool isNeeded() const override { return !entries.empty(); } + bool isNeeded() const override; void addSymbols(); template void addEntry(Symbol &sym); @@ -679,7 +679,18 @@ private: std::vector entries; - bool isIplt; +}; + +class IpltSection final : public SyntheticSection { + std::vector entries; + +public: + IpltSection(); + void writeTo(uint8_t *buf) override; + size_t getSize() const override; + bool isNeeded() const override { return !entries.empty(); } + void addSymbols(); + template void addEntry(Symbol &sym); }; class GdbIndexSection final : public SyntheticSection { @@ -1162,7 +1173,7 @@ SyntheticSection *partEnd; SyntheticSection *partIndex; PltSection *plt; - PltSection *iplt; + IpltSection *iplt; PPC32Got2Section *ppc32Got2; RelocationBaseSection *relaPlt; RelocationBaseSection *relaIplt; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -2445,14 +2445,13 @@ // On PowerPC64 the lazy symbol resolvers go into the `global linkage table` // in the .glink section, rather then the typical .plt section. -PltSection::PltSection(bool isIplt) - : SyntheticSection( - SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, - (config->emachine == EM_PPC || config->emachine == EM_PPC64) - ? ".glink" - : ".plt"), - headerSize(!isIplt || config->zRetpolineplt ? target->pltHeaderSize : 0), - isIplt(isIplt) { +PltSection::PltSection() + : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"), + headerSize(target->pltHeaderSize) { + if (config->emachine == EM_PPC || config->emachine == EM_PPC64) { + name = ".glink"; + } + // The PLT needs to be writable on SPARC as the dynamic linker will // modify the instructions in the PLT entries. if (config->emachine == EM_SPARCV9) @@ -2465,10 +2464,9 @@ return; } - // At beginning of PLT or retpoline IPLT, we have code to call the dynamic + // At beginning of PLT, we have code to call the dynamic // linker to resolve dynsyms at runtime. Write such code. - if (headerSize) - target->writePltHeader(buf); + target->writePltHeader(buf); size_t off = headerSize; for (size_t i = 0, e = entries.size(); i != e; ++i) { @@ -2489,12 +2487,14 @@ return headerSize + entries.size() * target->pltEntrySize; } +bool PltSection::isNeeded() const { + return !entries.empty() || (config->zRetpolineplt && in.iplt->isNeeded()); +} + // Some architectures such as additional symbols in the PLT section. For // example ARM uses mapping symbols to aid disassembly void PltSection::addSymbols() { - // The PLT may have symbols defined for the Header, the IPLT has no header - if (!isIplt) - target->addPltHeaderSymbols(*this); + target->addPltHeaderSymbols(*this); size_t off = headerSize; for (size_t i = 0; i < entries.size(); ++i) { @@ -2503,6 +2503,40 @@ } } +IpltSection::IpltSection() + : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt") { + if (config->emachine == EM_PPC || config->emachine == EM_PPC64) { + name = ".glink"; + } +} + +void IpltSection::writeTo(uint8_t *buf) { + uint32_t off = 0; + for (const Symbol *sym : entries) { + target->writeIplt(buf + off, sym->getGotPltVA(), getVA() + off, + sym->pltIndex); + off += target->pltEntrySize; + } +} + +size_t IpltSection::getSize() const { + return entries.size() * target->ipltEntrySize; +} + +template void IpltSection::addEntry(Symbol &sym) { + sym.pltIndex = entries.size(); + entries.push_back(&sym); +} + +// ARM uses mapping symbols to aid disassembly. +void IpltSection::addSymbols() { + size_t off = 0; + for (size_t i = 0, e = entries.size(); i != e; ++i) { + target->addPltSymbols(*this, off); + off += target->pltEntrySize; + } +} + // The string hash function for .gdb_index. static uint32_t computeGdbHash(StringRef s) { uint32_t h = 0; @@ -3620,6 +3654,11 @@ template void PltSection::addEntry(Symbol &Sym); template void PltSection::addEntry(Symbol &Sym); +template void IpltSection::addEntry(Symbol &Sym); +template void IpltSection::addEntry(Symbol &Sym); +template void IpltSection::addEntry(Symbol &Sym); +template void IpltSection::addEntry(Symbol &Sym); + template class MipsAbiFlagsSection; template class MipsAbiFlagsSection; template class MipsAbiFlagsSection; diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -43,6 +43,11 @@ virtual void writePlt(uint8_t *buf, uint64_t gotEntryAddr, uint64_t pltEntryAddr, int32_t index) const {} + virtual void writeIplt(uint8_t *buf, uint64_t gotEntryAddr, + uint64_t pltEntryAddr, int32_t index) const { + // All but PPC64 use the same format for .plt and .iplt entries. + writePlt(buf, gotEntryAddr, pltEntryAddr, index); + } virtual void addPltHeaderSymbols(InputSection &isec) const {} virtual void addPltSymbols(InputSection &isec, uint64_t off) const {} @@ -101,6 +106,7 @@ RelType tlsOffsetRel; unsigned pltEntrySize; unsigned pltHeaderSize; + unsigned ipltEntrySize; // At least on x86_64 positions 1 and 2 are used by the first plt entry // to support lazy loading. diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -515,9 +515,9 @@ /*sort=*/false); add(in.relaIplt); - in.plt = make(false); + in.plt = make(); add(in.plt); - in.iplt = make(true); + in.iplt = make(); add(in.iplt); if (config->andFeatures)