Changeset View
Changeset View
Standalone View
Standalone View
contrib/llvm/tools/lld/ELF/Arch/X86.cpp
Show All 15 Lines | |||||
using namespace llvm; | using namespace llvm; | ||||
using namespace llvm::support::endian; | using namespace llvm::support::endian; | ||||
using namespace llvm::ELF; | using namespace llvm::ELF; | ||||
using namespace lld; | using namespace lld; | ||||
using namespace lld::elf; | using namespace lld::elf; | ||||
namespace { | namespace { | ||||
class X86 final : public TargetInfo { | class X86 : public TargetInfo { | ||||
public: | public: | ||||
X86(); | X86(); | ||||
RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, | RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, | ||||
const uint8_t *Loc) const override; | const uint8_t *Loc) const override; | ||||
int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; | int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; | ||||
void writeGotPltHeader(uint8_t *Buf) const override; | void writeGotPltHeader(uint8_t *Buf) const override; | ||||
uint32_t getDynRel(uint32_t Type) const override; | uint32_t getDynRel(uint32_t Type) const override; | ||||
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; | void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; | ||||
▲ Show 20 Lines • Show All 320 Lines • ▼ Show 20 Lines | void X86::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { | ||||
const uint8_t Inst[] = { | const uint8_t Inst[] = { | ||||
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax | 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax | ||||
0x90, // nop | 0x90, // nop | ||||
0x8d, 0x74, 0x26, 0x00 // leal 0(%esi,1),%esi | 0x8d, 0x74, 0x26, 0x00 // leal 0(%esi,1),%esi | ||||
}; | }; | ||||
memcpy(Loc - 2, Inst, sizeof(Inst)); | memcpy(Loc - 2, Inst, sizeof(Inst)); | ||||
} | } | ||||
namespace { | |||||
class RetpolinePic : public X86 { | |||||
public: | |||||
RetpolinePic(); | |||||
void writeGotPlt(uint8_t *Buf, const SymbolBody &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; | |||||
}; | |||||
class RetpolineNoPic : public X86 { | |||||
public: | |||||
RetpolineNoPic(); | |||||
void writeGotPlt(uint8_t *Buf, const SymbolBody &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; | |||||
}; | |||||
} // namespace | |||||
RetpolinePic::RetpolinePic() { | |||||
PltHeaderSize = 48; | |||||
PltEntrySize = 32; | |||||
} | |||||
void RetpolinePic::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const { | |||||
write32le(Buf, S.getPltVA() + 17); | |||||
} | |||||
void RetpolinePic::writePltHeader(uint8_t *Buf) const { | |||||
const uint8_t Insn[] = { | |||||
0xff, 0xb3, 0, 0, 0, 0, // 0: pushl GOTPLT+4(%ebx) | |||||
0x50, // 6: pushl %eax | |||||
0x8b, 0x83, 0, 0, 0, 0, // 7: mov GOTPLT+8(%ebx), %eax | |||||
0xe8, 0x0e, 0x00, 0x00, 0x00, // d: call next | |||||
0xf3, 0x90, // 12: loop: pause | |||||
0x0f, 0xae, 0xe8, // 14: lfence | |||||
0xeb, 0xf9, // 17: jmp loop | |||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 | |||||
0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) | |||||
0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx | |||||
0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) | |||||
0x89, 0xc8, // 2b: mov %ecx, %eax | |||||
0x59, // 2d: pop %ecx | |||||
0xc3, // 2e: ret | |||||
0xcc, // 2f: int3 | |||||
}; | |||||
memcpy(Buf, Insn, sizeof(Insn)); | |||||
assert(sizeof(Insn) == TargetInfo::PltHeaderSize); | |||||
uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); | |||||
uint32_t GotPlt = InX::GotPlt->getVA() - Ebx; | |||||
write32le(Buf + 2, GotPlt + 4); | |||||
write32le(Buf + 9, GotPlt + 8); | |||||
} | |||||
void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, | |||||
uint64_t PltEntryAddr, int32_t Index, | |||||
unsigned RelOff) const { | |||||
const uint8_t Insn[] = { | |||||
0x50, // pushl %eax | |||||
0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax | |||||
0xe8, 0, 0, 0, 0, // call plt+0x20 | |||||
0xe9, 0, 0, 0, 0, // jmp plt+0x12 | |||||
0x68, 0, 0, 0, 0, // pushl $reloc_offset | |||||
0xe9, 0, 0, 0, 0, // jmp plt+0 | |||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, | |||||
}; | |||||
memcpy(Buf, Insn, sizeof(Insn)); | |||||
assert(sizeof(Insn) == TargetInfo::PltEntrySize); | |||||
uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); | |||||
write32le(Buf + 3, GotPltEntryAddr - Ebx); | |||||
write32le(Buf + 8, -Index * PltEntrySize - PltHeaderSize - 12 + 32); | |||||
write32le(Buf + 13, -Index * PltEntrySize - PltHeaderSize - 17 + 18); | |||||
write32le(Buf + 18, RelOff); | |||||
write32le(Buf + 23, -Index * PltEntrySize - PltHeaderSize - 27); | |||||
} | |||||
RetpolineNoPic::RetpolineNoPic() { | |||||
PltHeaderSize = 48; | |||||
PltEntrySize = 32; | |||||
} | |||||
void RetpolineNoPic::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const { | |||||
write32le(Buf, S.getPltVA() + 16); | |||||
} | |||||
void RetpolineNoPic::writePltHeader(uint8_t *Buf) const { | |||||
const uint8_t PltData[] = { | |||||
0xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+4 | |||||
0x50, // 6: pushl %eax | |||||
0xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax | |||||
0xe8, 0x0f, 0x00, 0x00, 0x00, // c: call next | |||||
0xf3, 0x90, // 11: loop: pause | |||||
0x0f, 0xae, 0xe8, // 13: lfence | |||||
0xeb, 0xf9, // 16: jmp loop | |||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 18: int3 | |||||
0xcc, 0xcc, 0xcc, // 1f: int3; .align 16 | |||||
0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) | |||||
0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx | |||||
0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) | |||||
0x89, 0xc8, // 2b: mov %ecx, %eax | |||||
0x59, // 2d: pop %ecx | |||||
0xc3, // 2e: ret | |||||
0xcc, // 2f: int3 | |||||
}; | |||||
memcpy(Buf, PltData, sizeof(PltData)); | |||||
assert(sizeof(PltData) == TargetInfo::PltHeaderSize); | |||||
uint32_t GotPlt = InX::GotPlt->getVA(); | |||||
write32le(Buf + 2, GotPlt + 4); | |||||
write32le(Buf + 8, GotPlt + 8); | |||||
} | |||||
void RetpolineNoPic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, | |||||
uint64_t PltEntryAddr, int32_t Index, | |||||
unsigned RelOff) const { | |||||
const uint8_t Insn[] = { | |||||
0x50, // 0: pushl %eax | |||||
0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax | |||||
0xe8, 0, 0, 0, 0, // 6: call plt+0x20 | |||||
0xe9, 0, 0, 0, 0, // b: jmp plt+0x11 | |||||
0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset | |||||
0xe9, 0, 0, 0, 0, // 15: jmp plt+0 | |||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, | |||||
}; | |||||
memcpy(Buf, Insn, sizeof(Insn)); | |||||
assert(sizeof(Insn) == TargetInfo::PltEntrySize); | |||||
write32le(Buf + 2, GotPltEntryAddr); | |||||
write32le(Buf + 7, -Index * PltEntrySize - PltHeaderSize - 11 + 32); | |||||
write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16 + 17); | |||||
write32le(Buf + 17, RelOff); | |||||
write32le(Buf + 22, -Index * PltEntrySize - PltHeaderSize - 26); | |||||
} | |||||
TargetInfo *elf::getX86TargetInfo() { | TargetInfo *elf::getX86TargetInfo() { | ||||
static X86 Target; | if (Config->ZRetpolineplt) { | ||||
return &Target; | if (Config->Pic) { | ||||
static RetpolinePic T; | |||||
return &T; | |||||
} | |||||
static RetpolineNoPic T; | |||||
return &T; | |||||
} | |||||
static X86 T; | |||||
return &T; | |||||
} | } |