10b57cec5SDimitry Andric //===- X86.cpp ------------------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "InputFiles.h" 100b57cec5SDimitry Andric #include "Symbols.h" 110b57cec5SDimitry Andric #include "SyntheticSections.h" 120b57cec5SDimitry Andric #include "Target.h" 130b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h" 140b57cec5SDimitry Andric #include "llvm/Support/Endian.h" 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric using namespace llvm; 170b57cec5SDimitry Andric using namespace llvm::support::endian; 180b57cec5SDimitry Andric using namespace llvm::ELF; 195ffd83dbSDimitry Andric using namespace lld; 205ffd83dbSDimitry Andric using namespace lld::elf; 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric namespace { 230b57cec5SDimitry Andric class X86 : public TargetInfo { 240b57cec5SDimitry Andric public: 250b57cec5SDimitry Andric X86(); 260b57cec5SDimitry Andric int getTlsGdRelaxSkip(RelType type) const override; 270b57cec5SDimitry Andric RelExpr getRelExpr(RelType type, const Symbol &s, 280b57cec5SDimitry Andric const uint8_t *loc) const override; 290b57cec5SDimitry Andric int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; 300b57cec5SDimitry Andric void writeGotPltHeader(uint8_t *buf) const override; 310b57cec5SDimitry Andric RelType getDynRel(RelType type) const override; 320b57cec5SDimitry Andric void writeGotPlt(uint8_t *buf, const Symbol &s) const override; 330b57cec5SDimitry Andric void writeIgotPlt(uint8_t *buf, const Symbol &s) const override; 340b57cec5SDimitry Andric void writePltHeader(uint8_t *buf) const override; 35480093f4SDimitry Andric void writePlt(uint8_t *buf, const Symbol &sym, 36480093f4SDimitry Andric uint64_t pltEntryAddr) const override; 375ffd83dbSDimitry Andric void relocate(uint8_t *loc, const Relocation &rel, 385ffd83dbSDimitry Andric uint64_t val) const override; 390b57cec5SDimitry Andric 40e8d8bef9SDimitry Andric RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override; 415ffd83dbSDimitry Andric void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, 425ffd83dbSDimitry Andric uint64_t val) const override; 435ffd83dbSDimitry Andric void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, 445ffd83dbSDimitry Andric uint64_t val) const override; 455ffd83dbSDimitry Andric void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, 465ffd83dbSDimitry Andric uint64_t val) const override; 475ffd83dbSDimitry Andric void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, 485ffd83dbSDimitry Andric uint64_t val) const override; 490b57cec5SDimitry Andric }; 500b57cec5SDimitry Andric } // namespace 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric X86::X86() { 530b57cec5SDimitry Andric copyRel = R_386_COPY; 540b57cec5SDimitry Andric gotRel = R_386_GLOB_DAT; 550b57cec5SDimitry Andric pltRel = R_386_JUMP_SLOT; 560b57cec5SDimitry Andric iRelativeRel = R_386_IRELATIVE; 570b57cec5SDimitry Andric relativeRel = R_386_RELATIVE; 580b57cec5SDimitry Andric symbolicRel = R_386_32; 59349cc55cSDimitry Andric tlsDescRel = R_386_TLS_DESC; 600b57cec5SDimitry Andric tlsGotRel = R_386_TLS_TPOFF; 610b57cec5SDimitry Andric tlsModuleIndexRel = R_386_TLS_DTPMOD32; 620b57cec5SDimitry Andric tlsOffsetRel = R_386_TLS_DTPOFF32; 63349cc55cSDimitry Andric gotBaseSymInGotPlt = true; 640b57cec5SDimitry Andric pltHeaderSize = 16; 65480093f4SDimitry Andric pltEntrySize = 16; 66480093f4SDimitry Andric ipltEntrySize = 16; 670b57cec5SDimitry Andric trapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric // Align to the non-PAE large page size (known as a superpage or huge page). 700b57cec5SDimitry Andric // FreeBSD automatically promotes large, superpage-aligned allocations. 710b57cec5SDimitry Andric defaultImageBase = 0x400000; 720b57cec5SDimitry Andric } 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric int X86::getTlsGdRelaxSkip(RelType type) const { 75349cc55cSDimitry Andric // TLSDESC relocations are processed separately. See relaxTlsGdToLe below. 76349cc55cSDimitry Andric return type == R_386_TLS_GOTDESC || type == R_386_TLS_DESC_CALL ? 1 : 2; 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric RelExpr X86::getRelExpr(RelType type, const Symbol &s, 800b57cec5SDimitry Andric const uint8_t *loc) const { 814824e7fdSDimitry Andric if (type == R_386_TLS_IE || type == R_386_TLS_GOTIE) 824824e7fdSDimitry Andric config->hasTlsIe = true; 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric switch (type) { 850b57cec5SDimitry Andric case R_386_8: 860b57cec5SDimitry Andric case R_386_16: 870b57cec5SDimitry Andric case R_386_32: 880b57cec5SDimitry Andric return R_ABS; 890b57cec5SDimitry Andric case R_386_TLS_LDO_32: 900b57cec5SDimitry Andric return R_DTPREL; 910b57cec5SDimitry Andric case R_386_TLS_GD: 920b57cec5SDimitry Andric return R_TLSGD_GOTPLT; 930b57cec5SDimitry Andric case R_386_TLS_LDM: 940b57cec5SDimitry Andric return R_TLSLD_GOTPLT; 950b57cec5SDimitry Andric case R_386_PLT32: 960b57cec5SDimitry Andric return R_PLT_PC; 970b57cec5SDimitry Andric case R_386_PC8: 980b57cec5SDimitry Andric case R_386_PC16: 990b57cec5SDimitry Andric case R_386_PC32: 1000b57cec5SDimitry Andric return R_PC; 1010b57cec5SDimitry Andric case R_386_GOTPC: 1020b57cec5SDimitry Andric return R_GOTPLTONLY_PC; 1030b57cec5SDimitry Andric case R_386_TLS_IE: 1040b57cec5SDimitry Andric return R_GOT; 1050b57cec5SDimitry Andric case R_386_GOT32: 1060b57cec5SDimitry Andric case R_386_GOT32X: 1070b57cec5SDimitry Andric // These relocations are arguably mis-designed because their calculations 1080b57cec5SDimitry Andric // depend on the instructions they are applied to. This is bad because we 1090b57cec5SDimitry Andric // usually don't care about whether the target section contains valid 1100b57cec5SDimitry Andric // machine instructions or not. But this is part of the documented ABI, so 1110b57cec5SDimitry Andric // we had to implement as the standard requires. 1120b57cec5SDimitry Andric // 1130b57cec5SDimitry Andric // x86 does not support PC-relative data access. Therefore, in order to 1140b57cec5SDimitry Andric // access GOT contents, a GOT address needs to be known at link-time 1150b57cec5SDimitry Andric // (which means non-PIC) or compilers have to emit code to get a GOT 1160b57cec5SDimitry Andric // address at runtime (which means code is position-independent but 1170b57cec5SDimitry Andric // compilers need to emit extra code for each GOT access.) This decision 1180b57cec5SDimitry Andric // is made at compile-time. In the latter case, compilers emit code to 119480093f4SDimitry Andric // load a GOT address to a register, which is usually %ebx. 1200b57cec5SDimitry Andric // 1210b57cec5SDimitry Andric // So, there are two ways to refer to symbol foo's GOT entry: foo@GOT or 1220b57cec5SDimitry Andric // foo@GOT(%ebx). 1230b57cec5SDimitry Andric // 1240b57cec5SDimitry Andric // foo@GOT is not usable in PIC. If we are creating a PIC output and if we 1250b57cec5SDimitry Andric // find such relocation, we should report an error. foo@GOT is resolved to 1260b57cec5SDimitry Andric // an *absolute* address of foo's GOT entry, because both GOT address and 1270b57cec5SDimitry Andric // foo's offset are known. In other words, it's G + A. 1280b57cec5SDimitry Andric // 1290b57cec5SDimitry Andric // foo@GOT(%ebx) needs to be resolved to a *relative* offset from a GOT to 1300b57cec5SDimitry Andric // foo's GOT entry in the table, because GOT address is not known but foo's 1310b57cec5SDimitry Andric // offset in the table is known. It's G + A - GOT. 1320b57cec5SDimitry Andric // 1330b57cec5SDimitry Andric // It's unfortunate that compilers emit the same relocation for these 1340b57cec5SDimitry Andric // different use cases. In order to distinguish them, we have to read a 1350b57cec5SDimitry Andric // machine instruction. 1360b57cec5SDimitry Andric // 1370b57cec5SDimitry Andric // The following code implements it. We assume that Loc[0] is the first byte 1380b57cec5SDimitry Andric // of a displacement or an immediate field of a valid machine 1390b57cec5SDimitry Andric // instruction. That means a ModRM byte is at Loc[-1]. By taking a look at 1400b57cec5SDimitry Andric // the byte, we can determine whether the instruction uses the operand as an 1410b57cec5SDimitry Andric // absolute address (R_GOT) or a register-relative address (R_GOTPLT). 1420b57cec5SDimitry Andric return (loc[-1] & 0xc7) == 0x5 ? R_GOT : R_GOTPLT; 143349cc55cSDimitry Andric case R_386_TLS_GOTDESC: 144349cc55cSDimitry Andric return R_TLSDESC_GOTPLT; 145349cc55cSDimitry Andric case R_386_TLS_DESC_CALL: 146349cc55cSDimitry Andric return R_TLSDESC_CALL; 1470b57cec5SDimitry Andric case R_386_TLS_GOTIE: 1480b57cec5SDimitry Andric return R_GOTPLT; 1490b57cec5SDimitry Andric case R_386_GOTOFF: 1500b57cec5SDimitry Andric return R_GOTPLTREL; 1510b57cec5SDimitry Andric case R_386_TLS_LE: 152e8d8bef9SDimitry Andric return R_TPREL; 1530b57cec5SDimitry Andric case R_386_TLS_LE_32: 154e8d8bef9SDimitry Andric return R_TPREL_NEG; 1550b57cec5SDimitry Andric case R_386_NONE: 1560b57cec5SDimitry Andric return R_NONE; 1570b57cec5SDimitry Andric default: 1580b57cec5SDimitry Andric error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + 1590b57cec5SDimitry Andric ") against symbol " + toString(s)); 1600b57cec5SDimitry Andric return R_NONE; 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 164e8d8bef9SDimitry Andric RelExpr X86::adjustTlsExpr(RelType type, RelExpr expr) const { 1650b57cec5SDimitry Andric switch (expr) { 1660b57cec5SDimitry Andric default: 1670b57cec5SDimitry Andric return expr; 1680b57cec5SDimitry Andric case R_RELAX_TLS_GD_TO_IE: 1690b57cec5SDimitry Andric return R_RELAX_TLS_GD_TO_IE_GOTPLT; 1700b57cec5SDimitry Andric case R_RELAX_TLS_GD_TO_LE: 171349cc55cSDimitry Andric return type == R_386_TLS_GD ? R_RELAX_TLS_GD_TO_LE_NEG 172349cc55cSDimitry Andric : R_RELAX_TLS_GD_TO_LE; 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric void X86::writeGotPltHeader(uint8_t *buf) const { 1770b57cec5SDimitry Andric write32le(buf, mainPart->dynamic->getVA()); 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric void X86::writeGotPlt(uint8_t *buf, const Symbol &s) const { 1810b57cec5SDimitry Andric // Entries in .got.plt initially points back to the corresponding 1820b57cec5SDimitry Andric // PLT entries with a fixed offset to skip the first instruction. 1830b57cec5SDimitry Andric write32le(buf, s.getPltVA() + 6); 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric void X86::writeIgotPlt(uint8_t *buf, const Symbol &s) const { 1870b57cec5SDimitry Andric // An x86 entry is the address of the ifunc resolver function. 1880b57cec5SDimitry Andric write32le(buf, s.getVA()); 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric RelType X86::getDynRel(RelType type) const { 1920b57cec5SDimitry Andric if (type == R_386_TLS_LE) 1930b57cec5SDimitry Andric return R_386_TLS_TPOFF; 1940b57cec5SDimitry Andric if (type == R_386_TLS_LE_32) 1950b57cec5SDimitry Andric return R_386_TLS_TPOFF32; 1960b57cec5SDimitry Andric return type; 1970b57cec5SDimitry Andric } 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric void X86::writePltHeader(uint8_t *buf) const { 2000b57cec5SDimitry Andric if (config->isPic) { 2010b57cec5SDimitry Andric const uint8_t v[] = { 2020b57cec5SDimitry Andric 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx) 2030b57cec5SDimitry Andric 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx) 2040b57cec5SDimitry Andric 0x90, 0x90, 0x90, 0x90 // nop 2050b57cec5SDimitry Andric }; 2060b57cec5SDimitry Andric memcpy(buf, v, sizeof(v)); 2070b57cec5SDimitry Andric return; 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric const uint8_t pltData[] = { 2110b57cec5SDimitry Andric 0xff, 0x35, 0, 0, 0, 0, // pushl (GOTPLT+4) 2120b57cec5SDimitry Andric 0xff, 0x25, 0, 0, 0, 0, // jmp *(GOTPLT+8) 2130b57cec5SDimitry Andric 0x90, 0x90, 0x90, 0x90, // nop 2140b57cec5SDimitry Andric }; 2150b57cec5SDimitry Andric memcpy(buf, pltData, sizeof(pltData)); 2160b57cec5SDimitry Andric uint32_t gotPlt = in.gotPlt->getVA(); 2170b57cec5SDimitry Andric write32le(buf + 2, gotPlt + 4); 2180b57cec5SDimitry Andric write32le(buf + 8, gotPlt + 8); 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric 221480093f4SDimitry Andric void X86::writePlt(uint8_t *buf, const Symbol &sym, 222480093f4SDimitry Andric uint64_t pltEntryAddr) const { 223*04eeddc0SDimitry Andric unsigned relOff = in.relaPlt->entsize * sym.getPltIdx(); 2240b57cec5SDimitry Andric if (config->isPic) { 2250b57cec5SDimitry Andric const uint8_t inst[] = { 2260b57cec5SDimitry Andric 0xff, 0xa3, 0, 0, 0, 0, // jmp *foo@GOT(%ebx) 2270b57cec5SDimitry Andric 0x68, 0, 0, 0, 0, // pushl $reloc_offset 2280b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC 2290b57cec5SDimitry Andric }; 2300b57cec5SDimitry Andric memcpy(buf, inst, sizeof(inst)); 231480093f4SDimitry Andric write32le(buf + 2, sym.getGotPltVA() - in.gotPlt->getVA()); 2320b57cec5SDimitry Andric } else { 2330b57cec5SDimitry Andric const uint8_t inst[] = { 2340b57cec5SDimitry Andric 0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT 2350b57cec5SDimitry Andric 0x68, 0, 0, 0, 0, // pushl $reloc_offset 2360b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC 2370b57cec5SDimitry Andric }; 2380b57cec5SDimitry Andric memcpy(buf, inst, sizeof(inst)); 239480093f4SDimitry Andric write32le(buf + 2, sym.getGotPltVA()); 2400b57cec5SDimitry Andric } 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric write32le(buf + 7, relOff); 243480093f4SDimitry Andric write32le(buf + 12, in.plt->getVA() - pltEntryAddr - 16); 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric int64_t X86::getImplicitAddend(const uint8_t *buf, RelType type) const { 2470b57cec5SDimitry Andric switch (type) { 2480b57cec5SDimitry Andric case R_386_8: 2490b57cec5SDimitry Andric case R_386_PC8: 2500b57cec5SDimitry Andric return SignExtend64<8>(*buf); 2510b57cec5SDimitry Andric case R_386_16: 2520b57cec5SDimitry Andric case R_386_PC16: 2530b57cec5SDimitry Andric return SignExtend64<16>(read16le(buf)); 2540b57cec5SDimitry Andric case R_386_32: 255fe6060f1SDimitry Andric case R_386_GLOB_DAT: 2560b57cec5SDimitry Andric case R_386_GOT32: 2570b57cec5SDimitry Andric case R_386_GOT32X: 2580b57cec5SDimitry Andric case R_386_GOTOFF: 2590b57cec5SDimitry Andric case R_386_GOTPC: 260fe6060f1SDimitry Andric case R_386_IRELATIVE: 2610b57cec5SDimitry Andric case R_386_PC32: 2620b57cec5SDimitry Andric case R_386_PLT32: 263fe6060f1SDimitry Andric case R_386_RELATIVE: 264349cc55cSDimitry Andric case R_386_TLS_GOTDESC: 265349cc55cSDimitry Andric case R_386_TLS_DESC_CALL: 266fe6060f1SDimitry Andric case R_386_TLS_DTPMOD32: 267fe6060f1SDimitry Andric case R_386_TLS_DTPOFF32: 2680b57cec5SDimitry Andric case R_386_TLS_LDO_32: 269fe6060f1SDimitry Andric case R_386_TLS_LDM: 270fe6060f1SDimitry Andric case R_386_TLS_IE: 271fe6060f1SDimitry Andric case R_386_TLS_IE_32: 2720b57cec5SDimitry Andric case R_386_TLS_LE: 273fe6060f1SDimitry Andric case R_386_TLS_LE_32: 274fe6060f1SDimitry Andric case R_386_TLS_GD: 275fe6060f1SDimitry Andric case R_386_TLS_GD_32: 276fe6060f1SDimitry Andric case R_386_TLS_GOTIE: 277fe6060f1SDimitry Andric case R_386_TLS_TPOFF: 278fe6060f1SDimitry Andric case R_386_TLS_TPOFF32: 2790b57cec5SDimitry Andric return SignExtend64<32>(read32le(buf)); 280349cc55cSDimitry Andric case R_386_TLS_DESC: 281349cc55cSDimitry Andric return SignExtend64<32>(read32le(buf + 4)); 282fe6060f1SDimitry Andric case R_386_NONE: 283fe6060f1SDimitry Andric case R_386_JUMP_SLOT: 284fe6060f1SDimitry Andric // These relocations are defined as not having an implicit addend. 285fe6060f1SDimitry Andric return 0; 2860b57cec5SDimitry Andric default: 287fe6060f1SDimitry Andric internalLinkerError(getErrorLocation(buf), 288fe6060f1SDimitry Andric "cannot read addend for relocation " + toString(type)); 2890b57cec5SDimitry Andric return 0; 2900b57cec5SDimitry Andric } 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric 2935ffd83dbSDimitry Andric void X86::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { 2945ffd83dbSDimitry Andric switch (rel.type) { 2950b57cec5SDimitry Andric case R_386_8: 2960b57cec5SDimitry Andric // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are 2970b57cec5SDimitry Andric // being used for some 16-bit programs such as boot loaders, so 2980b57cec5SDimitry Andric // we want to support them. 2995ffd83dbSDimitry Andric checkIntUInt(loc, val, 8, rel); 3000b57cec5SDimitry Andric *loc = val; 3010b57cec5SDimitry Andric break; 3020b57cec5SDimitry Andric case R_386_PC8: 3035ffd83dbSDimitry Andric checkInt(loc, val, 8, rel); 3040b57cec5SDimitry Andric *loc = val; 3050b57cec5SDimitry Andric break; 3060b57cec5SDimitry Andric case R_386_16: 3075ffd83dbSDimitry Andric checkIntUInt(loc, val, 16, rel); 3080b57cec5SDimitry Andric write16le(loc, val); 3090b57cec5SDimitry Andric break; 3100b57cec5SDimitry Andric case R_386_PC16: 3110b57cec5SDimitry Andric // R_386_PC16 is normally used with 16 bit code. In that situation 3120b57cec5SDimitry Andric // the PC is 16 bits, just like the addend. This means that it can 3130b57cec5SDimitry Andric // point from any 16 bit address to any other if the possibility 3140b57cec5SDimitry Andric // of wrapping is included. 3150b57cec5SDimitry Andric // The only restriction we have to check then is that the destination 3160b57cec5SDimitry Andric // address fits in 16 bits. That is impossible to do here. The problem is 3170b57cec5SDimitry Andric // that we are passed the final value, which already had the 3180b57cec5SDimitry Andric // current location subtracted from it. 3190b57cec5SDimitry Andric // We just check that Val fits in 17 bits. This misses some cases, but 3200b57cec5SDimitry Andric // should have no false positives. 3215ffd83dbSDimitry Andric checkInt(loc, val, 17, rel); 3220b57cec5SDimitry Andric write16le(loc, val); 3230b57cec5SDimitry Andric break; 3240b57cec5SDimitry Andric case R_386_32: 3250b57cec5SDimitry Andric case R_386_GOT32: 3260b57cec5SDimitry Andric case R_386_GOT32X: 3270b57cec5SDimitry Andric case R_386_GOTOFF: 3280b57cec5SDimitry Andric case R_386_GOTPC: 3290b57cec5SDimitry Andric case R_386_PC32: 3300b57cec5SDimitry Andric case R_386_PLT32: 3310b57cec5SDimitry Andric case R_386_RELATIVE: 332349cc55cSDimitry Andric case R_386_TLS_GOTDESC: 333349cc55cSDimitry Andric case R_386_TLS_DESC_CALL: 3340b57cec5SDimitry Andric case R_386_TLS_DTPMOD32: 3350b57cec5SDimitry Andric case R_386_TLS_DTPOFF32: 3360b57cec5SDimitry Andric case R_386_TLS_GD: 3370b57cec5SDimitry Andric case R_386_TLS_GOTIE: 3380b57cec5SDimitry Andric case R_386_TLS_IE: 3390b57cec5SDimitry Andric case R_386_TLS_LDM: 3400b57cec5SDimitry Andric case R_386_TLS_LDO_32: 3410b57cec5SDimitry Andric case R_386_TLS_LE: 3420b57cec5SDimitry Andric case R_386_TLS_LE_32: 3430b57cec5SDimitry Andric case R_386_TLS_TPOFF: 3440b57cec5SDimitry Andric case R_386_TLS_TPOFF32: 3455ffd83dbSDimitry Andric checkInt(loc, val, 32, rel); 3460b57cec5SDimitry Andric write32le(loc, val); 3470b57cec5SDimitry Andric break; 348349cc55cSDimitry Andric case R_386_TLS_DESC: 349349cc55cSDimitry Andric // The addend is stored in the second 32-bit word. 350349cc55cSDimitry Andric write32le(loc + 4, val); 351349cc55cSDimitry Andric break; 3520b57cec5SDimitry Andric default: 3530b57cec5SDimitry Andric llvm_unreachable("unknown relocation"); 3540b57cec5SDimitry Andric } 3550b57cec5SDimitry Andric } 3560b57cec5SDimitry Andric 357349cc55cSDimitry Andric void X86::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, 358349cc55cSDimitry Andric uint64_t val) const { 359349cc55cSDimitry Andric if (rel.type == R_386_TLS_GD) { 3600b57cec5SDimitry Andric // Convert 361349cc55cSDimitry Andric // leal x@tlsgd(, %ebx, 1), %eax 3620b57cec5SDimitry Andric // call __tls_get_addr@plt 3630b57cec5SDimitry Andric // to 3640b57cec5SDimitry Andric // movl %gs:0, %eax 365349cc55cSDimitry Andric // subl $x@tpoff, %eax 3660b57cec5SDimitry Andric const uint8_t inst[] = { 3670b57cec5SDimitry Andric 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 368349cc55cSDimitry Andric 0x81, 0xe8, 0, 0, 0, 0, // subl val(%ebx), %eax 3690b57cec5SDimitry Andric }; 3700b57cec5SDimitry Andric memcpy(loc - 3, inst, sizeof(inst)); 3710b57cec5SDimitry Andric write32le(loc + 5, val); 372349cc55cSDimitry Andric } else if (rel.type == R_386_TLS_GOTDESC) { 373349cc55cSDimitry Andric // Convert leal x@tlsdesc(%ebx), %eax to leal x@ntpoff, %eax. 374349cc55cSDimitry Andric // 375349cc55cSDimitry Andric // Note: call *x@tlsdesc(%eax) may not immediately follow this instruction. 376349cc55cSDimitry Andric if (memcmp(loc - 2, "\x8d\x83", 2)) { 377349cc55cSDimitry Andric error(getErrorLocation(loc - 2) + 378349cc55cSDimitry Andric "R_386_TLS_GOTDESC must be used in leal x@tlsdesc(%ebx), %eax"); 379349cc55cSDimitry Andric return; 380349cc55cSDimitry Andric } 381349cc55cSDimitry Andric loc[-1] = 0x05; 382349cc55cSDimitry Andric write32le(loc, val); 383349cc55cSDimitry Andric } else { 384349cc55cSDimitry Andric // Convert call *x@tlsdesc(%eax) to xchg ax, ax. 385349cc55cSDimitry Andric assert(rel.type == R_386_TLS_DESC_CALL); 386349cc55cSDimitry Andric loc[0] = 0x66; 387349cc55cSDimitry Andric loc[1] = 0x90; 388349cc55cSDimitry Andric } 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric 391349cc55cSDimitry Andric void X86::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, 392349cc55cSDimitry Andric uint64_t val) const { 393349cc55cSDimitry Andric if (rel.type == R_386_TLS_GD) { 3940b57cec5SDimitry Andric // Convert 395349cc55cSDimitry Andric // leal x@tlsgd(, %ebx, 1), %eax 3960b57cec5SDimitry Andric // call __tls_get_addr@plt 3970b57cec5SDimitry Andric // to 3980b57cec5SDimitry Andric // movl %gs:0, %eax 3990b57cec5SDimitry Andric // addl x@gotntpoff(%ebx), %eax 4000b57cec5SDimitry Andric const uint8_t inst[] = { 4010b57cec5SDimitry Andric 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 402349cc55cSDimitry Andric 0x03, 0x83, 0, 0, 0, 0, // addl val(%ebx), %eax 4030b57cec5SDimitry Andric }; 4040b57cec5SDimitry Andric memcpy(loc - 3, inst, sizeof(inst)); 4050b57cec5SDimitry Andric write32le(loc + 5, val); 406349cc55cSDimitry Andric } else if (rel.type == R_386_TLS_GOTDESC) { 407349cc55cSDimitry Andric // Convert leal x@tlsdesc(%ebx), %eax to movl x@gotntpoff(%ebx), %eax. 408349cc55cSDimitry Andric if (memcmp(loc - 2, "\x8d\x83", 2)) { 409349cc55cSDimitry Andric error(getErrorLocation(loc - 2) + 410349cc55cSDimitry Andric "R_386_TLS_GOTDESC must be used in leal x@tlsdesc(%ebx), %eax"); 411349cc55cSDimitry Andric return; 412349cc55cSDimitry Andric } 413349cc55cSDimitry Andric loc[-2] = 0x8b; 414349cc55cSDimitry Andric write32le(loc, val); 415349cc55cSDimitry Andric } else { 416349cc55cSDimitry Andric // Convert call *x@tlsdesc(%eax) to xchg ax, ax. 417349cc55cSDimitry Andric assert(rel.type == R_386_TLS_DESC_CALL); 418349cc55cSDimitry Andric loc[0] = 0x66; 419349cc55cSDimitry Andric loc[1] = 0x90; 420349cc55cSDimitry Andric } 4210b57cec5SDimitry Andric } 4220b57cec5SDimitry Andric 4230b57cec5SDimitry Andric // In some conditions, relocations can be optimized to avoid using GOT. 4240b57cec5SDimitry Andric // This function does that for Initial Exec to Local Exec case. 4255ffd83dbSDimitry Andric void X86::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, 4265ffd83dbSDimitry Andric uint64_t val) const { 4270b57cec5SDimitry Andric // Ulrich's document section 6.2 says that @gotntpoff can 4280b57cec5SDimitry Andric // be used with MOVL or ADDL instructions. 4290b57cec5SDimitry Andric // @indntpoff is similar to @gotntpoff, but for use in 4300b57cec5SDimitry Andric // position dependent code. 4310b57cec5SDimitry Andric uint8_t reg = (loc[-1] >> 3) & 7; 4320b57cec5SDimitry Andric 4335ffd83dbSDimitry Andric if (rel.type == R_386_TLS_IE) { 4340b57cec5SDimitry Andric if (loc[-1] == 0xa1) { 4350b57cec5SDimitry Andric // "movl foo@indntpoff,%eax" -> "movl $foo,%eax" 4360b57cec5SDimitry Andric // This case is different from the generic case below because 4370b57cec5SDimitry Andric // this is a 5 byte instruction while below is 6 bytes. 4380b57cec5SDimitry Andric loc[-1] = 0xb8; 4390b57cec5SDimitry Andric } else if (loc[-2] == 0x8b) { 4400b57cec5SDimitry Andric // "movl foo@indntpoff,%reg" -> "movl $foo,%reg" 4410b57cec5SDimitry Andric loc[-2] = 0xc7; 4420b57cec5SDimitry Andric loc[-1] = 0xc0 | reg; 4430b57cec5SDimitry Andric } else { 4440b57cec5SDimitry Andric // "addl foo@indntpoff,%reg" -> "addl $foo,%reg" 4450b57cec5SDimitry Andric loc[-2] = 0x81; 4460b57cec5SDimitry Andric loc[-1] = 0xc0 | reg; 4470b57cec5SDimitry Andric } 4480b57cec5SDimitry Andric } else { 4495ffd83dbSDimitry Andric assert(rel.type == R_386_TLS_GOTIE); 4500b57cec5SDimitry Andric if (loc[-2] == 0x8b) { 4510b57cec5SDimitry Andric // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg" 4520b57cec5SDimitry Andric loc[-2] = 0xc7; 4530b57cec5SDimitry Andric loc[-1] = 0xc0 | reg; 4540b57cec5SDimitry Andric } else { 4550b57cec5SDimitry Andric // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg" 4560b57cec5SDimitry Andric loc[-2] = 0x8d; 4570b57cec5SDimitry Andric loc[-1] = 0x80 | (reg << 3) | reg; 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric } 4600b57cec5SDimitry Andric write32le(loc, val); 4610b57cec5SDimitry Andric } 4620b57cec5SDimitry Andric 4635ffd83dbSDimitry Andric void X86::relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, 4645ffd83dbSDimitry Andric uint64_t val) const { 4655ffd83dbSDimitry Andric if (rel.type == R_386_TLS_LDO_32) { 4660b57cec5SDimitry Andric write32le(loc, val); 4670b57cec5SDimitry Andric return; 4680b57cec5SDimitry Andric } 4690b57cec5SDimitry Andric 4700b57cec5SDimitry Andric // Convert 4710b57cec5SDimitry Andric // leal foo(%reg),%eax 4720b57cec5SDimitry Andric // call ___tls_get_addr 4730b57cec5SDimitry Andric // to 4740b57cec5SDimitry Andric // movl %gs:0,%eax 4750b57cec5SDimitry Andric // nop 4760b57cec5SDimitry Andric // leal 0(%esi,1),%esi 4770b57cec5SDimitry Andric const uint8_t inst[] = { 4780b57cec5SDimitry Andric 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax 4790b57cec5SDimitry Andric 0x90, // nop 4800b57cec5SDimitry Andric 0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi 4810b57cec5SDimitry Andric }; 4820b57cec5SDimitry Andric memcpy(loc - 2, inst, sizeof(inst)); 4830b57cec5SDimitry Andric } 4840b57cec5SDimitry Andric 485480093f4SDimitry Andric // If Intel Indirect Branch Tracking is enabled, we have to emit special PLT 486480093f4SDimitry Andric // entries containing endbr32 instructions. A PLT entry will be split into two 487480093f4SDimitry Andric // parts, one in .plt.sec (writePlt), and the other in .plt (writeIBTPlt). 488480093f4SDimitry Andric namespace { 489480093f4SDimitry Andric class IntelIBT : public X86 { 490480093f4SDimitry Andric public: 491480093f4SDimitry Andric IntelIBT(); 492480093f4SDimitry Andric void writeGotPlt(uint8_t *buf, const Symbol &s) const override; 493480093f4SDimitry Andric void writePlt(uint8_t *buf, const Symbol &sym, 494480093f4SDimitry Andric uint64_t pltEntryAddr) const override; 495480093f4SDimitry Andric void writeIBTPlt(uint8_t *buf, size_t numEntries) const override; 496480093f4SDimitry Andric 497480093f4SDimitry Andric static const unsigned IBTPltHeaderSize = 16; 498480093f4SDimitry Andric }; 499480093f4SDimitry Andric } // namespace 500480093f4SDimitry Andric 501480093f4SDimitry Andric IntelIBT::IntelIBT() { pltHeaderSize = 0; } 502480093f4SDimitry Andric 503480093f4SDimitry Andric void IntelIBT::writeGotPlt(uint8_t *buf, const Symbol &s) const { 504480093f4SDimitry Andric uint64_t va = 505*04eeddc0SDimitry Andric in.ibtPlt->getVA() + IBTPltHeaderSize + s.getPltIdx() * pltEntrySize; 506480093f4SDimitry Andric write32le(buf, va); 507480093f4SDimitry Andric } 508480093f4SDimitry Andric 509480093f4SDimitry Andric void IntelIBT::writePlt(uint8_t *buf, const Symbol &sym, 510480093f4SDimitry Andric uint64_t /*pltEntryAddr*/) const { 511480093f4SDimitry Andric if (config->isPic) { 512480093f4SDimitry Andric const uint8_t inst[] = { 513480093f4SDimitry Andric 0xf3, 0x0f, 0x1e, 0xfb, // endbr32 514480093f4SDimitry Andric 0xff, 0xa3, 0, 0, 0, 0, // jmp *name@GOT(%ebx) 515480093f4SDimitry Andric 0x66, 0x0f, 0x1f, 0x44, 0, 0, // nop 516480093f4SDimitry Andric }; 517480093f4SDimitry Andric memcpy(buf, inst, sizeof(inst)); 518480093f4SDimitry Andric write32le(buf + 6, sym.getGotPltVA() - in.gotPlt->getVA()); 519480093f4SDimitry Andric return; 520480093f4SDimitry Andric } 521480093f4SDimitry Andric 522480093f4SDimitry Andric const uint8_t inst[] = { 523480093f4SDimitry Andric 0xf3, 0x0f, 0x1e, 0xfb, // endbr32 524480093f4SDimitry Andric 0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT 525480093f4SDimitry Andric 0x66, 0x0f, 0x1f, 0x44, 0, 0, // nop 526480093f4SDimitry Andric }; 527480093f4SDimitry Andric memcpy(buf, inst, sizeof(inst)); 528480093f4SDimitry Andric write32le(buf + 6, sym.getGotPltVA()); 529480093f4SDimitry Andric } 530480093f4SDimitry Andric 531480093f4SDimitry Andric void IntelIBT::writeIBTPlt(uint8_t *buf, size_t numEntries) const { 532480093f4SDimitry Andric writePltHeader(buf); 533480093f4SDimitry Andric buf += IBTPltHeaderSize; 534480093f4SDimitry Andric 535480093f4SDimitry Andric const uint8_t inst[] = { 536480093f4SDimitry Andric 0xf3, 0x0f, 0x1e, 0xfb, // endbr32 537480093f4SDimitry Andric 0x68, 0, 0, 0, 0, // pushl $reloc_offset 538480093f4SDimitry Andric 0xe9, 0, 0, 0, 0, // jmpq .PLT0@PC 539480093f4SDimitry Andric 0x66, 0x90, // nop 540480093f4SDimitry Andric }; 541480093f4SDimitry Andric 542480093f4SDimitry Andric for (size_t i = 0; i < numEntries; ++i) { 543480093f4SDimitry Andric memcpy(buf, inst, sizeof(inst)); 544480093f4SDimitry Andric write32le(buf + 5, i * sizeof(object::ELF32LE::Rel)); 545480093f4SDimitry Andric write32le(buf + 10, -pltHeaderSize - sizeof(inst) * i - 30); 546480093f4SDimitry Andric buf += sizeof(inst); 547480093f4SDimitry Andric } 548480093f4SDimitry Andric } 549480093f4SDimitry Andric 5500b57cec5SDimitry Andric namespace { 5510b57cec5SDimitry Andric class RetpolinePic : public X86 { 5520b57cec5SDimitry Andric public: 5530b57cec5SDimitry Andric RetpolinePic(); 5540b57cec5SDimitry Andric void writeGotPlt(uint8_t *buf, const Symbol &s) const override; 5550b57cec5SDimitry Andric void writePltHeader(uint8_t *buf) const override; 556480093f4SDimitry Andric void writePlt(uint8_t *buf, const Symbol &sym, 557480093f4SDimitry Andric uint64_t pltEntryAddr) const override; 5580b57cec5SDimitry Andric }; 5590b57cec5SDimitry Andric 5600b57cec5SDimitry Andric class RetpolineNoPic : public X86 { 5610b57cec5SDimitry Andric public: 5620b57cec5SDimitry Andric RetpolineNoPic(); 5630b57cec5SDimitry Andric void writeGotPlt(uint8_t *buf, const Symbol &s) const override; 5640b57cec5SDimitry Andric void writePltHeader(uint8_t *buf) const override; 565480093f4SDimitry Andric void writePlt(uint8_t *buf, const Symbol &sym, 566480093f4SDimitry Andric uint64_t pltEntryAddr) const override; 5670b57cec5SDimitry Andric }; 5680b57cec5SDimitry Andric } // namespace 5690b57cec5SDimitry Andric 5700b57cec5SDimitry Andric RetpolinePic::RetpolinePic() { 5710b57cec5SDimitry Andric pltHeaderSize = 48; 5720b57cec5SDimitry Andric pltEntrySize = 32; 573480093f4SDimitry Andric ipltEntrySize = 32; 5740b57cec5SDimitry Andric } 5750b57cec5SDimitry Andric 5760b57cec5SDimitry Andric void RetpolinePic::writeGotPlt(uint8_t *buf, const Symbol &s) const { 5770b57cec5SDimitry Andric write32le(buf, s.getPltVA() + 17); 5780b57cec5SDimitry Andric } 5790b57cec5SDimitry Andric 5800b57cec5SDimitry Andric void RetpolinePic::writePltHeader(uint8_t *buf) const { 5810b57cec5SDimitry Andric const uint8_t insn[] = { 5820b57cec5SDimitry Andric 0xff, 0xb3, 4, 0, 0, 0, // 0: pushl 4(%ebx) 5830b57cec5SDimitry Andric 0x50, // 6: pushl %eax 5840b57cec5SDimitry Andric 0x8b, 0x83, 8, 0, 0, 0, // 7: mov 8(%ebx), %eax 5850b57cec5SDimitry Andric 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: call next 5860b57cec5SDimitry Andric 0xf3, 0x90, // 12: loop: pause 5870b57cec5SDimitry Andric 0x0f, 0xae, 0xe8, // 14: lfence 5880b57cec5SDimitry Andric 0xeb, 0xf9, // 17: jmp loop 5890b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 5900b57cec5SDimitry Andric 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) 5910b57cec5SDimitry Andric 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx 5920b57cec5SDimitry Andric 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) 5930b57cec5SDimitry Andric 0x89, 0xc8, // 2b: mov %ecx, %eax 5940b57cec5SDimitry Andric 0x59, // 2d: pop %ecx 5950b57cec5SDimitry Andric 0xc3, // 2e: ret 5960b57cec5SDimitry Andric 0xcc, // 2f: int3; padding 5970b57cec5SDimitry Andric }; 5980b57cec5SDimitry Andric memcpy(buf, insn, sizeof(insn)); 5990b57cec5SDimitry Andric } 6000b57cec5SDimitry Andric 601480093f4SDimitry Andric void RetpolinePic::writePlt(uint8_t *buf, const Symbol &sym, 602480093f4SDimitry Andric uint64_t pltEntryAddr) const { 603*04eeddc0SDimitry Andric unsigned relOff = in.relaPlt->entsize * sym.getPltIdx(); 6040b57cec5SDimitry Andric const uint8_t insn[] = { 6050b57cec5SDimitry Andric 0x50, // pushl %eax 6060b57cec5SDimitry Andric 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax 6070b57cec5SDimitry Andric 0xe8, 0, 0, 0, 0, // call plt+0x20 6080b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // jmp plt+0x12 6090b57cec5SDimitry Andric 0x68, 0, 0, 0, 0, // pushl $reloc_offset 6100b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // jmp plt+0 6110b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding 6120b57cec5SDimitry Andric }; 6130b57cec5SDimitry Andric memcpy(buf, insn, sizeof(insn)); 6140b57cec5SDimitry Andric 6150b57cec5SDimitry Andric uint32_t ebx = in.gotPlt->getVA(); 616480093f4SDimitry Andric unsigned off = pltEntryAddr - in.plt->getVA(); 617480093f4SDimitry Andric write32le(buf + 3, sym.getGotPltVA() - ebx); 6180b57cec5SDimitry Andric write32le(buf + 8, -off - 12 + 32); 6190b57cec5SDimitry Andric write32le(buf + 13, -off - 17 + 18); 6200b57cec5SDimitry Andric write32le(buf + 18, relOff); 6210b57cec5SDimitry Andric write32le(buf + 23, -off - 27); 6220b57cec5SDimitry Andric } 6230b57cec5SDimitry Andric 6240b57cec5SDimitry Andric RetpolineNoPic::RetpolineNoPic() { 6250b57cec5SDimitry Andric pltHeaderSize = 48; 6260b57cec5SDimitry Andric pltEntrySize = 32; 627480093f4SDimitry Andric ipltEntrySize = 32; 6280b57cec5SDimitry Andric } 6290b57cec5SDimitry Andric 6300b57cec5SDimitry Andric void RetpolineNoPic::writeGotPlt(uint8_t *buf, const Symbol &s) const { 6310b57cec5SDimitry Andric write32le(buf, s.getPltVA() + 16); 6320b57cec5SDimitry Andric } 6330b57cec5SDimitry Andric 6340b57cec5SDimitry Andric void RetpolineNoPic::writePltHeader(uint8_t *buf) const { 6350b57cec5SDimitry Andric const uint8_t insn[] = { 6360b57cec5SDimitry Andric 0xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+4 6370b57cec5SDimitry Andric 0x50, // 6: pushl %eax 6380b57cec5SDimitry Andric 0xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax 6390b57cec5SDimitry Andric 0xe8, 0x0f, 0x00, 0x00, 0x00, // c: call next 6400b57cec5SDimitry Andric 0xf3, 0x90, // 11: loop: pause 6410b57cec5SDimitry Andric 0x0f, 0xae, 0xe8, // 13: lfence 6420b57cec5SDimitry Andric 0xeb, 0xf9, // 16: jmp loop 6430b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 18: int3 6440b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, // 1f: int3; .align 16 6450b57cec5SDimitry Andric 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) 6460b57cec5SDimitry Andric 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx 6470b57cec5SDimitry Andric 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) 6480b57cec5SDimitry Andric 0x89, 0xc8, // 2b: mov %ecx, %eax 6490b57cec5SDimitry Andric 0x59, // 2d: pop %ecx 6500b57cec5SDimitry Andric 0xc3, // 2e: ret 6510b57cec5SDimitry Andric 0xcc, // 2f: int3; padding 6520b57cec5SDimitry Andric }; 6530b57cec5SDimitry Andric memcpy(buf, insn, sizeof(insn)); 6540b57cec5SDimitry Andric 6550b57cec5SDimitry Andric uint32_t gotPlt = in.gotPlt->getVA(); 6560b57cec5SDimitry Andric write32le(buf + 2, gotPlt + 4); 6570b57cec5SDimitry Andric write32le(buf + 8, gotPlt + 8); 6580b57cec5SDimitry Andric } 6590b57cec5SDimitry Andric 660480093f4SDimitry Andric void RetpolineNoPic::writePlt(uint8_t *buf, const Symbol &sym, 661480093f4SDimitry Andric uint64_t pltEntryAddr) const { 662*04eeddc0SDimitry Andric unsigned relOff = in.relaPlt->entsize * sym.getPltIdx(); 6630b57cec5SDimitry Andric const uint8_t insn[] = { 6640b57cec5SDimitry Andric 0x50, // 0: pushl %eax 6650b57cec5SDimitry Andric 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax 6660b57cec5SDimitry Andric 0xe8, 0, 0, 0, 0, // 6: call plt+0x20 6670b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11 6680b57cec5SDimitry Andric 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset 6690b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // 15: jmp plt+0 6700b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding 6710b57cec5SDimitry Andric 0xcc, // 1f: int3; padding 6720b57cec5SDimitry Andric }; 6730b57cec5SDimitry Andric memcpy(buf, insn, sizeof(insn)); 6740b57cec5SDimitry Andric 675480093f4SDimitry Andric unsigned off = pltEntryAddr - in.plt->getVA(); 676480093f4SDimitry Andric write32le(buf + 2, sym.getGotPltVA()); 6770b57cec5SDimitry Andric write32le(buf + 7, -off - 11 + 32); 6780b57cec5SDimitry Andric write32le(buf + 12, -off - 16 + 17); 6790b57cec5SDimitry Andric write32le(buf + 17, relOff); 6800b57cec5SDimitry Andric write32le(buf + 22, -off - 26); 6810b57cec5SDimitry Andric } 6820b57cec5SDimitry Andric 6835ffd83dbSDimitry Andric TargetInfo *elf::getX86TargetInfo() { 6840b57cec5SDimitry Andric if (config->zRetpolineplt) { 6850b57cec5SDimitry Andric if (config->isPic) { 6860b57cec5SDimitry Andric static RetpolinePic t; 6870b57cec5SDimitry Andric return &t; 6880b57cec5SDimitry Andric } 6890b57cec5SDimitry Andric static RetpolineNoPic t; 6900b57cec5SDimitry Andric return &t; 6910b57cec5SDimitry Andric } 6920b57cec5SDimitry Andric 693480093f4SDimitry Andric if (config->andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT) { 694480093f4SDimitry Andric static IntelIBT t; 695480093f4SDimitry Andric return &t; 696480093f4SDimitry Andric } 697480093f4SDimitry Andric 6980b57cec5SDimitry Andric static X86 t; 6990b57cec5SDimitry Andric return &t; 7000b57cec5SDimitry Andric } 701