Path: blob/main/contrib/llvm-project/lld/ELF/Arch/X86.cpp
34878 views
//===- X86.cpp ------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "OutputSections.h"9#include "Symbols.h"10#include "SyntheticSections.h"11#include "Target.h"12#include "lld/Common/ErrorHandler.h"13#include "llvm/Support/Endian.h"1415using namespace llvm;16using namespace llvm::support::endian;17using namespace llvm::ELF;18using namespace lld;19using namespace lld::elf;2021namespace {22class X86 : public TargetInfo {23public:24X86();25int getTlsGdRelaxSkip(RelType type) const override;26RelExpr getRelExpr(RelType type, const Symbol &s,27const uint8_t *loc) const override;28int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;29void writeGotPltHeader(uint8_t *buf) const override;30RelType getDynRel(RelType type) const override;31void writeGotPlt(uint8_t *buf, const Symbol &s) const override;32void writeIgotPlt(uint8_t *buf, const Symbol &s) const override;33void writePltHeader(uint8_t *buf) const override;34void writePlt(uint8_t *buf, const Symbol &sym,35uint64_t pltEntryAddr) const override;36void relocate(uint8_t *loc, const Relocation &rel,37uint64_t val) const override;3839RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;40void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;41};42} // namespace4344X86::X86() {45copyRel = R_386_COPY;46gotRel = R_386_GLOB_DAT;47pltRel = R_386_JUMP_SLOT;48iRelativeRel = R_386_IRELATIVE;49relativeRel = R_386_RELATIVE;50symbolicRel = R_386_32;51tlsDescRel = R_386_TLS_DESC;52tlsGotRel = R_386_TLS_TPOFF;53tlsModuleIndexRel = R_386_TLS_DTPMOD32;54tlsOffsetRel = R_386_TLS_DTPOFF32;55gotBaseSymInGotPlt = true;56pltHeaderSize = 16;57pltEntrySize = 16;58ipltEntrySize = 16;59trapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT36061// Align to the non-PAE large page size (known as a superpage or huge page).62// FreeBSD automatically promotes large, superpage-aligned allocations.63defaultImageBase = 0x400000;64}6566int X86::getTlsGdRelaxSkip(RelType type) const {67// TLSDESC relocations are processed separately. See relaxTlsGdToLe below.68return type == R_386_TLS_GOTDESC || type == R_386_TLS_DESC_CALL ? 1 : 2;69}7071RelExpr X86::getRelExpr(RelType type, const Symbol &s,72const uint8_t *loc) const {73switch (type) {74case R_386_8:75case R_386_16:76case R_386_32:77return R_ABS;78case R_386_TLS_LDO_32:79return R_DTPREL;80case R_386_TLS_GD:81return R_TLSGD_GOTPLT;82case R_386_TLS_LDM:83return R_TLSLD_GOTPLT;84case R_386_PLT32:85return R_PLT_PC;86case R_386_PC8:87case R_386_PC16:88case R_386_PC32:89return R_PC;90case R_386_GOTPC:91return R_GOTPLTONLY_PC;92case R_386_TLS_IE:93return R_GOT;94case R_386_GOT32:95case R_386_GOT32X:96// These relocations are arguably mis-designed because their calculations97// depend on the instructions they are applied to. This is bad because we98// usually don't care about whether the target section contains valid99// machine instructions or not. But this is part of the documented ABI, so100// we had to implement as the standard requires.101//102// x86 does not support PC-relative data access. Therefore, in order to103// access GOT contents, a GOT address needs to be known at link-time104// (which means non-PIC) or compilers have to emit code to get a GOT105// address at runtime (which means code is position-independent but106// compilers need to emit extra code for each GOT access.) This decision107// is made at compile-time. In the latter case, compilers emit code to108// load a GOT address to a register, which is usually %ebx.109//110// So, there are two ways to refer to symbol foo's GOT entry: foo@GOT or111// foo@GOT(%ebx).112//113// foo@GOT is not usable in PIC. If we are creating a PIC output and if we114// find such relocation, we should report an error. foo@GOT is resolved to115// an *absolute* address of foo's GOT entry, because both GOT address and116// foo's offset are known. In other words, it's G + A.117//118// foo@GOT(%ebx) needs to be resolved to a *relative* offset from a GOT to119// foo's GOT entry in the table, because GOT address is not known but foo's120// offset in the table is known. It's G + A - GOT.121//122// It's unfortunate that compilers emit the same relocation for these123// different use cases. In order to distinguish them, we have to read a124// machine instruction.125//126// The following code implements it. We assume that Loc[0] is the first byte127// of a displacement or an immediate field of a valid machine128// instruction. That means a ModRM byte is at Loc[-1]. By taking a look at129// the byte, we can determine whether the instruction uses the operand as an130// absolute address (R_GOT) or a register-relative address (R_GOTPLT).131return (loc[-1] & 0xc7) == 0x5 ? R_GOT : R_GOTPLT;132case R_386_TLS_GOTDESC:133return R_TLSDESC_GOTPLT;134case R_386_TLS_DESC_CALL:135return R_TLSDESC_CALL;136case R_386_TLS_GOTIE:137return R_GOTPLT;138case R_386_GOTOFF:139return R_GOTPLTREL;140case R_386_TLS_LE:141return R_TPREL;142case R_386_TLS_LE_32:143return R_TPREL_NEG;144case R_386_NONE:145return R_NONE;146default:147error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +148") against symbol " + toString(s));149return R_NONE;150}151}152153RelExpr X86::adjustTlsExpr(RelType type, RelExpr expr) const {154switch (expr) {155default:156return expr;157case R_RELAX_TLS_GD_TO_IE:158return R_RELAX_TLS_GD_TO_IE_GOTPLT;159case R_RELAX_TLS_GD_TO_LE:160return type == R_386_TLS_GD ? R_RELAX_TLS_GD_TO_LE_NEG161: R_RELAX_TLS_GD_TO_LE;162}163}164165void X86::writeGotPltHeader(uint8_t *buf) const {166write32le(buf, mainPart->dynamic->getVA());167}168169void X86::writeGotPlt(uint8_t *buf, const Symbol &s) const {170// Entries in .got.plt initially points back to the corresponding171// PLT entries with a fixed offset to skip the first instruction.172write32le(buf, s.getPltVA() + 6);173}174175void X86::writeIgotPlt(uint8_t *buf, const Symbol &s) const {176// An x86 entry is the address of the ifunc resolver function.177write32le(buf, s.getVA());178}179180RelType X86::getDynRel(RelType type) const {181if (type == R_386_TLS_LE)182return R_386_TLS_TPOFF;183if (type == R_386_TLS_LE_32)184return R_386_TLS_TPOFF32;185return type;186}187188void X86::writePltHeader(uint8_t *buf) const {189if (config->isPic) {190const uint8_t v[] = {1910xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx)1920xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx)1930x90, 0x90, 0x90, 0x90 // nop194};195memcpy(buf, v, sizeof(v));196return;197}198199const uint8_t pltData[] = {2000xff, 0x35, 0, 0, 0, 0, // pushl (GOTPLT+4)2010xff, 0x25, 0, 0, 0, 0, // jmp *(GOTPLT+8)2020x90, 0x90, 0x90, 0x90, // nop203};204memcpy(buf, pltData, sizeof(pltData));205uint32_t gotPlt = in.gotPlt->getVA();206write32le(buf + 2, gotPlt + 4);207write32le(buf + 8, gotPlt + 8);208}209210void X86::writePlt(uint8_t *buf, const Symbol &sym,211uint64_t pltEntryAddr) const {212unsigned relOff = in.relaPlt->entsize * sym.getPltIdx();213if (config->isPic) {214const uint8_t inst[] = {2150xff, 0xa3, 0, 0, 0, 0, // jmp *foo@GOT(%ebx)2160x68, 0, 0, 0, 0, // pushl $reloc_offset2170xe9, 0, 0, 0, 0, // jmp .PLT0@PC218};219memcpy(buf, inst, sizeof(inst));220write32le(buf + 2, sym.getGotPltVA() - in.gotPlt->getVA());221} else {222const uint8_t inst[] = {2230xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT2240x68, 0, 0, 0, 0, // pushl $reloc_offset2250xe9, 0, 0, 0, 0, // jmp .PLT0@PC226};227memcpy(buf, inst, sizeof(inst));228write32le(buf + 2, sym.getGotPltVA());229}230231write32le(buf + 7, relOff);232write32le(buf + 12, in.plt->getVA() - pltEntryAddr - 16);233}234235int64_t X86::getImplicitAddend(const uint8_t *buf, RelType type) const {236switch (type) {237case R_386_8:238case R_386_PC8:239return SignExtend64<8>(*buf);240case R_386_16:241case R_386_PC16:242return SignExtend64<16>(read16le(buf));243case R_386_32:244case R_386_GLOB_DAT:245case R_386_GOT32:246case R_386_GOT32X:247case R_386_GOTOFF:248case R_386_GOTPC:249case R_386_IRELATIVE:250case R_386_PC32:251case R_386_PLT32:252case R_386_RELATIVE:253case R_386_TLS_GOTDESC:254case R_386_TLS_DESC_CALL:255case R_386_TLS_DTPMOD32:256case R_386_TLS_DTPOFF32:257case R_386_TLS_LDO_32:258case R_386_TLS_LDM:259case R_386_TLS_IE:260case R_386_TLS_IE_32:261case R_386_TLS_LE:262case R_386_TLS_LE_32:263case R_386_TLS_GD:264case R_386_TLS_GD_32:265case R_386_TLS_GOTIE:266case R_386_TLS_TPOFF:267case R_386_TLS_TPOFF32:268return SignExtend64<32>(read32le(buf));269case R_386_TLS_DESC:270return SignExtend64<32>(read32le(buf + 4));271case R_386_NONE:272case R_386_JUMP_SLOT:273// These relocations are defined as not having an implicit addend.274return 0;275default:276internalLinkerError(getErrorLocation(buf),277"cannot read addend for relocation " + toString(type));278return 0;279}280}281282void X86::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {283switch (rel.type) {284case R_386_8:285// R_386_{PC,}{8,16} are not part of the i386 psABI, but they are286// being used for some 16-bit programs such as boot loaders, so287// we want to support them.288checkIntUInt(loc, val, 8, rel);289*loc = val;290break;291case R_386_PC8:292checkInt(loc, val, 8, rel);293*loc = val;294break;295case R_386_16:296checkIntUInt(loc, val, 16, rel);297write16le(loc, val);298break;299case R_386_PC16:300// R_386_PC16 is normally used with 16 bit code. In that situation301// the PC is 16 bits, just like the addend. This means that it can302// point from any 16 bit address to any other if the possibility303// of wrapping is included.304// The only restriction we have to check then is that the destination305// address fits in 16 bits. That is impossible to do here. The problem is306// that we are passed the final value, which already had the307// current location subtracted from it.308// We just check that Val fits in 17 bits. This misses some cases, but309// should have no false positives.310checkInt(loc, val, 17, rel);311write16le(loc, val);312break;313case R_386_32:314case R_386_GOT32:315case R_386_GOT32X:316case R_386_GOTOFF:317case R_386_GOTPC:318case R_386_PC32:319case R_386_PLT32:320case R_386_RELATIVE:321case R_386_TLS_GOTDESC:322case R_386_TLS_DESC_CALL:323case R_386_TLS_DTPMOD32:324case R_386_TLS_DTPOFF32:325case R_386_TLS_GD:326case R_386_TLS_GOTIE:327case R_386_TLS_IE:328case R_386_TLS_LDM:329case R_386_TLS_LDO_32:330case R_386_TLS_LE:331case R_386_TLS_LE_32:332case R_386_TLS_TPOFF:333case R_386_TLS_TPOFF32:334checkInt(loc, val, 32, rel);335write32le(loc, val);336break;337case R_386_TLS_DESC:338// The addend is stored in the second 32-bit word.339write32le(loc + 4, val);340break;341default:342llvm_unreachable("unknown relocation");343}344}345346static void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) {347if (rel.type == R_386_TLS_GD) {348// Convert (loc[-2] == 0x04)349// leal x@tlsgd(, %ebx, 1), %eax350// call ___tls_get_addr@plt351// or352// leal x@tlsgd(%reg), %eax353// call *___tls_get_addr@got(%reg)354// to355const uint8_t inst[] = {3560x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax3570x81, 0xe8, 0, 0, 0, 0, // subl x@ntpoff(%ebx), %eax358};359uint8_t *w = loc[-2] == 0x04 ? loc - 3 : loc - 2;360memcpy(w, inst, sizeof(inst));361write32le(w + 8, val);362} else if (rel.type == R_386_TLS_GOTDESC) {363// Convert leal x@tlsdesc(%ebx), %eax to leal x@ntpoff, %eax.364//365// Note: call *x@tlsdesc(%eax) may not immediately follow this instruction.366if (memcmp(loc - 2, "\x8d\x83", 2)) {367error(getErrorLocation(loc - 2) +368"R_386_TLS_GOTDESC must be used in leal x@tlsdesc(%ebx), %eax");369return;370}371loc[-1] = 0x05;372write32le(loc, val);373} else {374// Convert call *x@tlsdesc(%eax) to xchg ax, ax.375assert(rel.type == R_386_TLS_DESC_CALL);376loc[0] = 0x66;377loc[1] = 0x90;378}379}380381static void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) {382if (rel.type == R_386_TLS_GD) {383// Convert (loc[-2] == 0x04)384// leal x@tlsgd(, %ebx, 1), %eax385// call ___tls_get_addr@plt386// or387// leal x@tlsgd(%reg), %eax388// call *___tls_get_addr@got(%reg)389const uint8_t inst[] = {3900x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax3910x03, 0x83, 0, 0, 0, 0, // addl x@gottpoff(%ebx), %eax392};393uint8_t *w = loc[-2] == 0x04 ? loc - 3 : loc - 2;394memcpy(w, inst, sizeof(inst));395write32le(w + 8, val);396} else if (rel.type == R_386_TLS_GOTDESC) {397// Convert leal x@tlsdesc(%ebx), %eax to movl x@gotntpoff(%ebx), %eax.398if (memcmp(loc - 2, "\x8d\x83", 2)) {399error(getErrorLocation(loc - 2) +400"R_386_TLS_GOTDESC must be used in leal x@tlsdesc(%ebx), %eax");401return;402}403loc[-2] = 0x8b;404write32le(loc, val);405} else {406// Convert call *x@tlsdesc(%eax) to xchg ax, ax.407assert(rel.type == R_386_TLS_DESC_CALL);408loc[0] = 0x66;409loc[1] = 0x90;410}411}412413// In some conditions, relocations can be optimized to avoid using GOT.414// This function does that for Initial Exec to Local Exec case.415static void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) {416// Ulrich's document section 6.2 says that @gotntpoff can417// be used with MOVL or ADDL instructions.418// @indntpoff is similar to @gotntpoff, but for use in419// position dependent code.420uint8_t reg = (loc[-1] >> 3) & 7;421422if (rel.type == R_386_TLS_IE) {423if (loc[-1] == 0xa1) {424// "movl foo@indntpoff,%eax" -> "movl $foo,%eax"425// This case is different from the generic case below because426// this is a 5 byte instruction while below is 6 bytes.427loc[-1] = 0xb8;428} else if (loc[-2] == 0x8b) {429// "movl foo@indntpoff,%reg" -> "movl $foo,%reg"430loc[-2] = 0xc7;431loc[-1] = 0xc0 | reg;432} else {433// "addl foo@indntpoff,%reg" -> "addl $foo,%reg"434loc[-2] = 0x81;435loc[-1] = 0xc0 | reg;436}437} else {438assert(rel.type == R_386_TLS_GOTIE);439if (loc[-2] == 0x8b) {440// "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg"441loc[-2] = 0xc7;442loc[-1] = 0xc0 | reg;443} else {444// "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg"445loc[-2] = 0x8d;446loc[-1] = 0x80 | (reg << 3) | reg;447}448}449write32le(loc, val);450}451452static void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) {453if (rel.type == R_386_TLS_LDO_32) {454write32le(loc, val);455return;456}457458if (loc[4] == 0xe8) {459// Convert460// leal x(%reg),%eax461// call ___tls_get_addr@plt462// to463const uint8_t inst[] = {4640x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax4650x90, // nop4660x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi467};468memcpy(loc - 2, inst, sizeof(inst));469return;470}471472// Convert473// leal x(%reg),%eax474// call *___tls_get_addr@got(%reg)475// to476const uint8_t inst[] = {4770x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax4780x8d, 0xb6, 0x00, 0x00, 0x00, 0x00, // leal (%esi),%esi479};480memcpy(loc - 2, inst, sizeof(inst));481}482483void X86::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {484uint64_t secAddr = sec.getOutputSection()->addr;485if (auto *s = dyn_cast<InputSection>(&sec))486secAddr += s->outSecOff;487for (const Relocation &rel : sec.relocs()) {488uint8_t *loc = buf + rel.offset;489const uint64_t val = SignExtend64(490sec.getRelocTargetVA(sec.file, rel.type, rel.addend,491secAddr + rel.offset, *rel.sym, rel.expr),49232);493switch (rel.expr) {494case R_RELAX_TLS_GD_TO_IE_GOTPLT:495relaxTlsGdToIe(loc, rel, val);496continue;497case R_RELAX_TLS_GD_TO_LE:498case R_RELAX_TLS_GD_TO_LE_NEG:499relaxTlsGdToLe(loc, rel, val);500continue;501case R_RELAX_TLS_LD_TO_LE:502relaxTlsLdToLe(loc, rel, val);503break;504case R_RELAX_TLS_IE_TO_LE:505relaxTlsIeToLe(loc, rel, val);506continue;507default:508relocate(loc, rel, val);509break;510}511}512}513514// If Intel Indirect Branch Tracking is enabled, we have to emit special PLT515// entries containing endbr32 instructions. A PLT entry will be split into two516// parts, one in .plt.sec (writePlt), and the other in .plt (writeIBTPlt).517namespace {518class IntelIBT : public X86 {519public:520IntelIBT();521void writeGotPlt(uint8_t *buf, const Symbol &s) const override;522void writePlt(uint8_t *buf, const Symbol &sym,523uint64_t pltEntryAddr) const override;524void writeIBTPlt(uint8_t *buf, size_t numEntries) const override;525526static const unsigned IBTPltHeaderSize = 16;527};528} // namespace529530IntelIBT::IntelIBT() { pltHeaderSize = 0; }531532void IntelIBT::writeGotPlt(uint8_t *buf, const Symbol &s) const {533uint64_t va =534in.ibtPlt->getVA() + IBTPltHeaderSize + s.getPltIdx() * pltEntrySize;535write32le(buf, va);536}537538void IntelIBT::writePlt(uint8_t *buf, const Symbol &sym,539uint64_t /*pltEntryAddr*/) const {540if (config->isPic) {541const uint8_t inst[] = {5420xf3, 0x0f, 0x1e, 0xfb, // endbr325430xff, 0xa3, 0, 0, 0, 0, // jmp *name@GOT(%ebx)5440x66, 0x0f, 0x1f, 0x44, 0, 0, // nop545};546memcpy(buf, inst, sizeof(inst));547write32le(buf + 6, sym.getGotPltVA() - in.gotPlt->getVA());548return;549}550551const uint8_t inst[] = {5520xf3, 0x0f, 0x1e, 0xfb, // endbr325530xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT5540x66, 0x0f, 0x1f, 0x44, 0, 0, // nop555};556memcpy(buf, inst, sizeof(inst));557write32le(buf + 6, sym.getGotPltVA());558}559560void IntelIBT::writeIBTPlt(uint8_t *buf, size_t numEntries) const {561writePltHeader(buf);562buf += IBTPltHeaderSize;563564const uint8_t inst[] = {5650xf3, 0x0f, 0x1e, 0xfb, // endbr325660x68, 0, 0, 0, 0, // pushl $reloc_offset5670xe9, 0, 0, 0, 0, // jmpq .PLT0@PC5680x66, 0x90, // nop569};570571for (size_t i = 0; i < numEntries; ++i) {572memcpy(buf, inst, sizeof(inst));573write32le(buf + 5, i * sizeof(object::ELF32LE::Rel));574write32le(buf + 10, -pltHeaderSize - sizeof(inst) * i - 30);575buf += sizeof(inst);576}577}578579namespace {580class RetpolinePic : public X86 {581public:582RetpolinePic();583void writeGotPlt(uint8_t *buf, const Symbol &s) const override;584void writePltHeader(uint8_t *buf) const override;585void writePlt(uint8_t *buf, const Symbol &sym,586uint64_t pltEntryAddr) const override;587};588589class RetpolineNoPic : public X86 {590public:591RetpolineNoPic();592void writeGotPlt(uint8_t *buf, const Symbol &s) const override;593void writePltHeader(uint8_t *buf) const override;594void writePlt(uint8_t *buf, const Symbol &sym,595uint64_t pltEntryAddr) const override;596};597} // namespace598599RetpolinePic::RetpolinePic() {600pltHeaderSize = 48;601pltEntrySize = 32;602ipltEntrySize = 32;603}604605void RetpolinePic::writeGotPlt(uint8_t *buf, const Symbol &s) const {606write32le(buf, s.getPltVA() + 17);607}608609void RetpolinePic::writePltHeader(uint8_t *buf) const {610const uint8_t insn[] = {6110xff, 0xb3, 4, 0, 0, 0, // 0: pushl 4(%ebx)6120x50, // 6: pushl %eax6130x8b, 0x83, 8, 0, 0, 0, // 7: mov 8(%ebx), %eax6140xe8, 0x0e, 0x00, 0x00, 0x00, // d: call next6150xf3, 0x90, // 12: loop: pause6160x0f, 0xae, 0xe8, // 14: lfence6170xeb, 0xf9, // 17: jmp loop6180xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 166190x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp)6200x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx6210x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp)6220x89, 0xc8, // 2b: mov %ecx, %eax6230x59, // 2d: pop %ecx6240xc3, // 2e: ret6250xcc, // 2f: int3; padding626};627memcpy(buf, insn, sizeof(insn));628}629630void RetpolinePic::writePlt(uint8_t *buf, const Symbol &sym,631uint64_t pltEntryAddr) const {632unsigned relOff = in.relaPlt->entsize * sym.getPltIdx();633const uint8_t insn[] = {6340x50, // pushl %eax6350x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax6360xe8, 0, 0, 0, 0, // call plt+0x206370xe9, 0, 0, 0, 0, // jmp plt+0x126380x68, 0, 0, 0, 0, // pushl $reloc_offset6390xe9, 0, 0, 0, 0, // jmp plt+06400xcc, 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding641};642memcpy(buf, insn, sizeof(insn));643644uint32_t ebx = in.gotPlt->getVA();645unsigned off = pltEntryAddr - in.plt->getVA();646write32le(buf + 3, sym.getGotPltVA() - ebx);647write32le(buf + 8, -off - 12 + 32);648write32le(buf + 13, -off - 17 + 18);649write32le(buf + 18, relOff);650write32le(buf + 23, -off - 27);651}652653RetpolineNoPic::RetpolineNoPic() {654pltHeaderSize = 48;655pltEntrySize = 32;656ipltEntrySize = 32;657}658659void RetpolineNoPic::writeGotPlt(uint8_t *buf, const Symbol &s) const {660write32le(buf, s.getPltVA() + 16);661}662663void RetpolineNoPic::writePltHeader(uint8_t *buf) const {664const uint8_t insn[] = {6650xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+46660x50, // 6: pushl %eax6670xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax6680xe8, 0x0f, 0x00, 0x00, 0x00, // c: call next6690xf3, 0x90, // 11: loop: pause6700x0f, 0xae, 0xe8, // 13: lfence6710xeb, 0xf9, // 16: jmp loop6720xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 18: int36730xcc, 0xcc, 0xcc, // 1f: int3; .align 166740x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp)6750x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx6760x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp)6770x89, 0xc8, // 2b: mov %ecx, %eax6780x59, // 2d: pop %ecx6790xc3, // 2e: ret6800xcc, // 2f: int3; padding681};682memcpy(buf, insn, sizeof(insn));683684uint32_t gotPlt = in.gotPlt->getVA();685write32le(buf + 2, gotPlt + 4);686write32le(buf + 8, gotPlt + 8);687}688689void RetpolineNoPic::writePlt(uint8_t *buf, const Symbol &sym,690uint64_t pltEntryAddr) const {691unsigned relOff = in.relaPlt->entsize * sym.getPltIdx();692const uint8_t insn[] = {6930x50, // 0: pushl %eax6940xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax6950xe8, 0, 0, 0, 0, // 6: call plt+0x206960xe9, 0, 0, 0, 0, // b: jmp plt+0x116970x68, 0, 0, 0, 0, // 10: pushl $reloc_offset6980xe9, 0, 0, 0, 0, // 15: jmp plt+06990xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding7000xcc, // 1f: int3; padding701};702memcpy(buf, insn, sizeof(insn));703704unsigned off = pltEntryAddr - in.plt->getVA();705write32le(buf + 2, sym.getGotPltVA());706write32le(buf + 7, -off - 11 + 32);707write32le(buf + 12, -off - 16 + 17);708write32le(buf + 17, relOff);709write32le(buf + 22, -off - 26);710}711712TargetInfo *elf::getX86TargetInfo() {713if (config->zRetpolineplt) {714if (config->isPic) {715static RetpolinePic t;716return &t;717}718static RetpolineNoPic t;719return &t;720}721722if (config->andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT) {723static IntelIBT t;724return &t;725}726727static X86 t;728return &t;729}730731732