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).
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 {
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;
}
gotPltHeaderEntriesNum = 0;
pltHeaderSize = 64; // size of PLTresolve in .glink
pltEntrySize = 4;
+ ipltEntrySize = 4;
needsThunks = true;
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;
// .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) {
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).
}
write32le(buf + 7, relOff);
- write32le(buf + 12, -pltHeaderSize - pltEntrySize * index - 16);
+ write32le(buf + 12, in.plt->getVA() - pltEntryAddr - 16);
}
int64_t X86::getImplicitAddend(const uint8_t *buf, RelType type) const {
RetpolinePic::RetpolinePic() {
pltHeaderSize = 48;
pltEntrySize = 32;
+ ipltEntrySize = 32;
}
void RetpolinePic::writeGotPlt(uint8_t *buf, const Symbol &s) const {
memcpy(buf, insn, sizeof(insn));
uint32_t ebx = in.gotPlt->getVA();
- unsigned off = pltHeaderSize + pltEntrySize * index;
+ unsigned off = pltEntryAddr - in.plt->getVA();
write32le(buf + 3, gotPltEntryAddr - ebx);
write32le(buf + 8, -off - 12 + 32);
write32le(buf + 13, -off - 17 + 18);
RetpolineNoPic::RetpolineNoPic() {
pltHeaderSize = 48;
pltEntrySize = 32;
+ ipltEntrySize = 32;
}
void RetpolineNoPic::writeGotPlt(uint8_t *buf, const Symbol &s) const {
};
memcpy(buf, insn, sizeof(insn));
- unsigned off = pltHeaderSize + pltEntrySize * index;
+ unsigned off = pltEntryAddr - in.plt->getVA();
write32le(buf + 2, gotPltEntryAddr);
write32le(buf + 7, -off - 11 + 32);
write32le(buf + 12, -off - 16 + 17);
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).
write32le(buf + 2, gotPltEntryAddr - pltEntryAddr - 6);
write32le(buf + 7, index);
- write32le(buf + 12, -pltHeaderSize - pltEntrySize * index - 16);
+ write32le(buf + 12, in.plt->getVA() - pltEntryAddr - 16);
}
RelType X86_64::getDynRel(RelType type) const {
Retpoline::Retpoline() {
pltHeaderSize = 48;
pltEntrySize = 32;
+ ipltEntrySize = 32;
}
void Retpoline::writeGotPlt(uint8_t *buf, const Symbol &s) const {
};
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);
RetpolineZNow::RetpolineZNow() {
pltHeaderSize = 32;
pltEntrySize = 16;
+ ipltEntrySize = 16;
}
void RetpolineZNow::writePltHeader(uint8_t *buf) const {
memcpy(buf, insn, sizeof(insn));
write32le(buf + 3, gotPltEntryAddr - pltEntryAddr - 7);
- write32le(buf + 8, -pltHeaderSize - pltEntrySize * index - 12);
+ write32le(buf + 8, in.plt->getVA() - pltEntryAddr - 12);
}
static TargetInfo *getTargetInfo() {
expr, type);
}
-template <class GotPltSection>
+template <class PltSection, class GotPltSection>
static void addPltEntry(PltSection *plt, GotPltSection *gotPlt,
RelocationBaseSection *rel, RelType type, Symbol &sym) {
plt->addEntry(sym);
} 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<Defined>(sym);
d.section = in.iplt;
- d.value = entryOffset;
+ d.value = sym.pltIndex * target->ipltEntrySize;
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.
}
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.
// 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)
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) {
return headerSize + entries.size() * target->pltEntrySize;
}
-// Some architectures such as additional symbols in the PLT section. For
-// example ARM uses mapping symbols to aid disassembly
+bool PltSection::isNeeded() const {
+ // For -z retpolineplt, .iplt needs the .plt header.
+ return !entries.empty() || (config->zRetpolineplt && in.iplt->isNeeded());
+}
+
+// Used by ARM to add mapping symbols in the PLT section, which 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) {
}
}
+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->ipltEntrySize;
+ }
+}
+
+size_t IpltSection::getSize() const {
+ return entries.size() * target->ipltEntrySize;
+}
+
+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;
size_t size = 0;
};
-// The PltSection is used for both the Plt and Iplt. The former usually has a
-// header as its first entry that is used at run-time to resolve lazy binding.
-// The latter is used for GNU Ifunc symbols, that will be subject to a
-// Target->IRelativeRel.
+// Used for PLT entries. It usually has a PLT header for lazy binding. Each PLT
+// entry is associated with a JUMP_SLOT relocation, which may be resolved lazily
+// at runtime.
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();
void addEntry(Symbol &sym);
private:
std::vector<const Symbol *> entries;
- bool isIplt;
+};
+
+// Used for non-preemptible ifuncs. It does not have a header. Each entry is
+// associated with an IRELATIVE relocation, which will be resolved eagerly at
+// runtime. PltSection cannot can only contain entries associated with JUMP_SLOT
+// relocations, so IPLT entries are in a separate section.
+class IpltSection final : public SyntheticSection {
+ std::vector<const Symbol *> entries;
+
+public:
+ IpltSection();
+ void writeTo(uint8_t *buf) override;
+ size_t getSize() const override;
+ bool isNeeded() const override { return !entries.empty(); }
+ void addSymbols();
+ void addEntry(Symbol &sym);
};
class GdbIndexSection final : public SyntheticSection {
SyntheticSection *partEnd;
SyntheticSection *partIndex;
PltSection *plt;
- PltSection *iplt;
+ IpltSection *iplt;
PPC32Got2Section *ppc32Got2;
RelocationBaseSection *relaPlt;
RelocationBaseSection *relaIplt;
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 {}
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.
/*sort=*/false);
add(in.relaIplt);
- in.plt = make<PltSection>(false);
+ in.plt = make<PltSection>();
add(in.plt);
- in.iplt = make<PltSection>(true);
+ in.iplt = make<IpltSection>();
add(in.iplt);
if (config->andFeatures)
// DISASM-NEXT: foo:
// DISASM-NEXT: 401100: jmpl *4202784
// DISASM-NEXT: pushl $0
-// DISASM-NEXT: jmp -32 <_start+0xa>
+// DISASM-NEXT: jmp -16 <foo>
// DISASM: bar:
// DISASM-NEXT: 401110: jmpl *4202788
// DISASM-NEXT: pushl $8
-// DISASM-NEXT: jmp -48 <_start+0xa>
+// DISASM-NEXT: jmp -32 <foo>
.text
.type foo STT_GNU_IFUNC
// DISASM-NEXT: jmp -48 <.plt>
// DISASM-NEXT: jmpl *4207276
// DISASM-NEXT: pushl $0
-// DISASM-NEXT: jmp -32 <zed2@plt>
+// DISASM-NEXT: jmp -64 <.plt>
// DISASM-NEXT: jmpl *4207280
// DISASM-NEXT: pushl $8
-// DISASM-NEXT: jmp -48 <zed2@plt>
+// DISASM-NEXT: jmp -80 <.plt>
.text
.type foo STT_GNU_IFUNC
// DISASM-NEXT: 20131b: jmp -48 <.plt>
// DISASM-NEXT: 201320: jmpq *8498(%rip)
// DISASM-NEXT: 201326: pushq $0
-// DISASM-NEXT: 20132b: jmp -32 <zed2@plt>
+// DISASM-NEXT: 20132b: jmp -64 <.plt>
// DISASM-NEXT: 201330: jmpq *8490(%rip)
// DISASM-NEXT: 201336: pushq $1
-// DISASM-NEXT: 20133b: jmp -48 <zed2@plt>
+// DISASM-NEXT: 20133b: jmp -80 <.plt>
.text
.type foo STT_GNU_IFUNC
// DISASM-NEXT: 134b: jmp -48 <.plt>
// DISASM-NEXT: 1350: jmpq *8466(%rip)
// DISASM-NEXT: 1356: pushq $0
-// DISASM-NEXT: 135b: jmp -32 <f2@plt>
+// DISASM-NEXT: 135b: jmp -64 <.plt>
// CHECK: Relocations [
// CHECK-NEXT: Section (5) .rela.dyn {
// DISASM-NEXT: .plt:
// DISASM-NEXT: 2011b0: {{.*}} jmpq *4122(%rip)
// DISASM-NEXT: 2011b6: {{.*}} pushq $0
-// DISASM-NEXT: 2011bb: {{.*}} jmp -32 <_start+0x16>
+// DISASM-NEXT: 2011bb: {{.*}} jmp -16 <.plt>
// DISASM-NEXT: 2011c0: {{.*}} jmpq *4114(%rip)
// DISASM-NEXT: 2011c6: {{.*}} pushq $1
-// DISASM-NEXT: 2011cb: {{.*}} jmp -48 <_start+0x16>
+// DISASM-NEXT: 2011cb: {{.*}} jmp -32 <.plt>
.text
.type foo STT_GNU_IFUNC