summaryrefslogtreecommitdiff
path: root/lld/ELF/Arch/X86.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/Arch/X86.cpp')
-rw-r--r--lld/ELF/Arch/X86.cpp121
1 files changed, 97 insertions, 24 deletions
diff --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp
index b27a6e302e78c..b4daedc0f5dce 100644
--- a/lld/ELF/Arch/X86.cpp
+++ b/lld/ELF/Arch/X86.cpp
@@ -33,8 +33,8 @@ public:
void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
void writeIgotPlt(uint8_t *buf, const Symbol &s) const override;
void writePltHeader(uint8_t *buf) const override;
- void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr,
- int32_t index, unsigned relOff) const override;
+ void writePlt(uint8_t *buf, const Symbol &sym,
+ uint64_t pltEntryAddr) const override;
void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override;
RelExpr adjustRelaxExpr(RelType type, const uint8_t *data,
@@ -57,8 +57,9 @@ X86::X86() {
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).
@@ -115,7 +116,7 @@ RelExpr X86::getRelExpr(RelType type, const Symbol &s,
// address at runtime (which means code is position-independent but
// compilers need to emit extra code for each GOT access.) This decision
// is made at compile-time. In the latter case, compilers emit code to
- // load an GOT address to a register, which is usually %ebx.
+ // load a GOT address to a register, which is usually %ebx.
//
// So, there are two ways to refer to symbol foo's GOT entry: foo@GOT or
// foo@GOT(%ebx).
@@ -213,9 +214,9 @@ void X86::writePltHeader(uint8_t *buf) const {
write32le(buf + 8, gotPlt + 8);
}
-void X86::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
- uint64_t pltEntryAddr, int32_t index,
- unsigned relOff) const {
+void X86::writePlt(uint8_t *buf, const Symbol &sym,
+ uint64_t pltEntryAddr) const {
+ unsigned relOff = in.relaPlt->entsize * sym.pltIndex;
if (config->isPic) {
const uint8_t inst[] = {
0xff, 0xa3, 0, 0, 0, 0, // jmp *foo@GOT(%ebx)
@@ -223,7 +224,7 @@ void X86::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
0xe9, 0, 0, 0, 0, // jmp .PLT0@PC
};
memcpy(buf, inst, sizeof(inst));
- write32le(buf + 2, gotPltEntryAddr - in.gotPlt->getVA());
+ write32le(buf + 2, sym.getGotPltVA() - in.gotPlt->getVA());
} else {
const uint8_t inst[] = {
0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT
@@ -231,11 +232,11 @@ void X86::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
0xe9, 0, 0, 0, 0, // jmp .PLT0@PC
};
memcpy(buf, inst, sizeof(inst));
- write32le(buf + 2, gotPltEntryAddr);
+ write32le(buf + 2, sym.getGotPltVA());
}
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 {
@@ -409,14 +410,79 @@ void X86::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const {
memcpy(loc - 2, inst, sizeof(inst));
}
+// If Intel Indirect Branch Tracking is enabled, we have to emit special PLT
+// entries containing endbr32 instructions. A PLT entry will be split into two
+// parts, one in .plt.sec (writePlt), and the other in .plt (writeIBTPlt).
+namespace {
+class IntelIBT : public X86 {
+public:
+ IntelIBT();
+ void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
+ void writePlt(uint8_t *buf, const Symbol &sym,
+ uint64_t pltEntryAddr) const override;
+ void writeIBTPlt(uint8_t *buf, size_t numEntries) const override;
+
+ static const unsigned IBTPltHeaderSize = 16;
+};
+} // namespace
+
+IntelIBT::IntelIBT() { pltHeaderSize = 0; }
+
+void IntelIBT::writeGotPlt(uint8_t *buf, const Symbol &s) const {
+ uint64_t va =
+ in.ibtPlt->getVA() + IBTPltHeaderSize + s.pltIndex * pltEntrySize;
+ write32le(buf, va);
+}
+
+void IntelIBT::writePlt(uint8_t *buf, const Symbol &sym,
+ uint64_t /*pltEntryAddr*/) const {
+ if (config->isPic) {
+ const uint8_t inst[] = {
+ 0xf3, 0x0f, 0x1e, 0xfb, // endbr32
+ 0xff, 0xa3, 0, 0, 0, 0, // jmp *name@GOT(%ebx)
+ 0x66, 0x0f, 0x1f, 0x44, 0, 0, // nop
+ };
+ memcpy(buf, inst, sizeof(inst));
+ write32le(buf + 6, sym.getGotPltVA() - in.gotPlt->getVA());
+ return;
+ }
+
+ const uint8_t inst[] = {
+ 0xf3, 0x0f, 0x1e, 0xfb, // endbr32
+ 0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT
+ 0x66, 0x0f, 0x1f, 0x44, 0, 0, // nop
+ };
+ memcpy(buf, inst, sizeof(inst));
+ write32le(buf + 6, sym.getGotPltVA());
+}
+
+void IntelIBT::writeIBTPlt(uint8_t *buf, size_t numEntries) const {
+ writePltHeader(buf);
+ buf += IBTPltHeaderSize;
+
+ const uint8_t inst[] = {
+ 0xf3, 0x0f, 0x1e, 0xfb, // endbr32
+ 0x68, 0, 0, 0, 0, // pushl $reloc_offset
+ 0xe9, 0, 0, 0, 0, // jmpq .PLT0@PC
+ 0x66, 0x90, // nop
+ };
+
+ for (size_t i = 0; i < numEntries; ++i) {
+ memcpy(buf, inst, sizeof(inst));
+ write32le(buf + 5, i * sizeof(object::ELF32LE::Rel));
+ write32le(buf + 10, -pltHeaderSize - sizeof(inst) * i - 30);
+ buf += sizeof(inst);
+ }
+}
+
namespace {
class RetpolinePic : public X86 {
public:
RetpolinePic();
void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
void writePltHeader(uint8_t *buf) const override;
- void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr,
- int32_t index, unsigned relOff) const override;
+ void writePlt(uint8_t *buf, const Symbol &sym,
+ uint64_t pltEntryAddr) const override;
};
class RetpolineNoPic : public X86 {
@@ -424,14 +490,15 @@ public:
RetpolineNoPic();
void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
void writePltHeader(uint8_t *buf) const override;
- void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr,
- int32_t index, unsigned relOff) const override;
+ void writePlt(uint8_t *buf, const Symbol &sym,
+ uint64_t pltEntryAddr) const override;
};
} // namespace
RetpolinePic::RetpolinePic() {
pltHeaderSize = 48;
pltEntrySize = 32;
+ ipltEntrySize = 32;
}
void RetpolinePic::writeGotPlt(uint8_t *buf, const Symbol &s) const {
@@ -459,9 +526,9 @@ void RetpolinePic::writePltHeader(uint8_t *buf) const {
memcpy(buf, insn, sizeof(insn));
}
-void RetpolinePic::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
- uint64_t pltEntryAddr, int32_t index,
- unsigned relOff) const {
+void RetpolinePic::writePlt(uint8_t *buf, const Symbol &sym,
+ uint64_t pltEntryAddr) const {
+ unsigned relOff = in.relaPlt->entsize * sym.pltIndex;
const uint8_t insn[] = {
0x50, // pushl %eax
0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax
@@ -474,8 +541,8 @@ void RetpolinePic::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
memcpy(buf, insn, sizeof(insn));
uint32_t ebx = in.gotPlt->getVA();
- unsigned off = pltHeaderSize + pltEntrySize * index;
- write32le(buf + 3, gotPltEntryAddr - ebx);
+ unsigned off = pltEntryAddr - in.plt->getVA();
+ write32le(buf + 3, sym.getGotPltVA() - ebx);
write32le(buf + 8, -off - 12 + 32);
write32le(buf + 13, -off - 17 + 18);
write32le(buf + 18, relOff);
@@ -485,6 +552,7 @@ void RetpolinePic::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
RetpolineNoPic::RetpolineNoPic() {
pltHeaderSize = 48;
pltEntrySize = 32;
+ ipltEntrySize = 32;
}
void RetpolineNoPic::writeGotPlt(uint8_t *buf, const Symbol &s) const {
@@ -517,9 +585,9 @@ void RetpolineNoPic::writePltHeader(uint8_t *buf) const {
write32le(buf + 8, gotPlt + 8);
}
-void RetpolineNoPic::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
- uint64_t pltEntryAddr, int32_t index,
- unsigned relOff) const {
+void RetpolineNoPic::writePlt(uint8_t *buf, const Symbol &sym,
+ uint64_t pltEntryAddr) const {
+ unsigned relOff = in.relaPlt->entsize * sym.pltIndex;
const uint8_t insn[] = {
0x50, // 0: pushl %eax
0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax
@@ -532,8 +600,8 @@ void RetpolineNoPic::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr,
};
memcpy(buf, insn, sizeof(insn));
- unsigned off = pltHeaderSize + pltEntrySize * index;
- write32le(buf + 2, gotPltEntryAddr);
+ unsigned off = pltEntryAddr - in.plt->getVA();
+ write32le(buf + 2, sym.getGotPltVA());
write32le(buf + 7, -off - 11 + 32);
write32le(buf + 12, -off - 16 + 17);
write32le(buf + 17, relOff);
@@ -550,6 +618,11 @@ TargetInfo *getX86TargetInfo() {
return &t;
}
+ if (config->andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT) {
+ static IntelIBT t;
+ return &t;
+ }
+
static X86 t;
return &t;
}