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 40*e8d8bef9SDimitry 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 noneRel = R_386_NONE; 560b57cec5SDimitry Andric pltRel = R_386_JUMP_SLOT; 570b57cec5SDimitry Andric iRelativeRel = R_386_IRELATIVE; 580b57cec5SDimitry Andric relativeRel = R_386_RELATIVE; 590b57cec5SDimitry Andric symbolicRel = R_386_32; 600b57cec5SDimitry Andric tlsGotRel = R_386_TLS_TPOFF; 610b57cec5SDimitry Andric tlsModuleIndexRel = R_386_TLS_DTPMOD32; 620b57cec5SDimitry Andric tlsOffsetRel = R_386_TLS_DTPOFF32; 630b57cec5SDimitry Andric pltHeaderSize = 16; 64480093f4SDimitry Andric pltEntrySize = 16; 65480093f4SDimitry Andric ipltEntrySize = 16; 660b57cec5SDimitry Andric trapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric // Align to the non-PAE large page size (known as a superpage or huge page). 690b57cec5SDimitry Andric // FreeBSD automatically promotes large, superpage-aligned allocations. 700b57cec5SDimitry Andric defaultImageBase = 0x400000; 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric int X86::getTlsGdRelaxSkip(RelType type) const { 740b57cec5SDimitry Andric return 2; 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric RelExpr X86::getRelExpr(RelType type, const Symbol &s, 780b57cec5SDimitry Andric const uint8_t *loc) const { 790b57cec5SDimitry Andric // There are 4 different TLS variable models with varying degrees of 800b57cec5SDimitry Andric // flexibility and performance. LocalExec and InitialExec models are fast but 810b57cec5SDimitry Andric // less-flexible models. If they are in use, we set DF_STATIC_TLS flag in the 820b57cec5SDimitry Andric // dynamic section to let runtime know about that. 830b57cec5SDimitry Andric if (type == R_386_TLS_LE || type == R_386_TLS_LE_32 || type == R_386_TLS_IE || 840b57cec5SDimitry Andric type == R_386_TLS_GOTIE) 850b57cec5SDimitry Andric config->hasStaticTlsModel = true; 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric switch (type) { 880b57cec5SDimitry Andric case R_386_8: 890b57cec5SDimitry Andric case R_386_16: 900b57cec5SDimitry Andric case R_386_32: 910b57cec5SDimitry Andric return R_ABS; 920b57cec5SDimitry Andric case R_386_TLS_LDO_32: 930b57cec5SDimitry Andric return R_DTPREL; 940b57cec5SDimitry Andric case R_386_TLS_GD: 950b57cec5SDimitry Andric return R_TLSGD_GOTPLT; 960b57cec5SDimitry Andric case R_386_TLS_LDM: 970b57cec5SDimitry Andric return R_TLSLD_GOTPLT; 980b57cec5SDimitry Andric case R_386_PLT32: 990b57cec5SDimitry Andric return R_PLT_PC; 1000b57cec5SDimitry Andric case R_386_PC8: 1010b57cec5SDimitry Andric case R_386_PC16: 1020b57cec5SDimitry Andric case R_386_PC32: 1030b57cec5SDimitry Andric return R_PC; 1040b57cec5SDimitry Andric case R_386_GOTPC: 1050b57cec5SDimitry Andric return R_GOTPLTONLY_PC; 1060b57cec5SDimitry Andric case R_386_TLS_IE: 1070b57cec5SDimitry Andric return R_GOT; 1080b57cec5SDimitry Andric case R_386_GOT32: 1090b57cec5SDimitry Andric case R_386_GOT32X: 1100b57cec5SDimitry Andric // These relocations are arguably mis-designed because their calculations 1110b57cec5SDimitry Andric // depend on the instructions they are applied to. This is bad because we 1120b57cec5SDimitry Andric // usually don't care about whether the target section contains valid 1130b57cec5SDimitry Andric // machine instructions or not. But this is part of the documented ABI, so 1140b57cec5SDimitry Andric // we had to implement as the standard requires. 1150b57cec5SDimitry Andric // 1160b57cec5SDimitry Andric // x86 does not support PC-relative data access. Therefore, in order to 1170b57cec5SDimitry Andric // access GOT contents, a GOT address needs to be known at link-time 1180b57cec5SDimitry Andric // (which means non-PIC) or compilers have to emit code to get a GOT 1190b57cec5SDimitry Andric // address at runtime (which means code is position-independent but 1200b57cec5SDimitry Andric // compilers need to emit extra code for each GOT access.) This decision 1210b57cec5SDimitry Andric // is made at compile-time. In the latter case, compilers emit code to 122480093f4SDimitry Andric // load a GOT address to a register, which is usually %ebx. 1230b57cec5SDimitry Andric // 1240b57cec5SDimitry Andric // So, there are two ways to refer to symbol foo's GOT entry: foo@GOT or 1250b57cec5SDimitry Andric // foo@GOT(%ebx). 1260b57cec5SDimitry Andric // 1270b57cec5SDimitry Andric // foo@GOT is not usable in PIC. If we are creating a PIC output and if we 1280b57cec5SDimitry Andric // find such relocation, we should report an error. foo@GOT is resolved to 1290b57cec5SDimitry Andric // an *absolute* address of foo's GOT entry, because both GOT address and 1300b57cec5SDimitry Andric // foo's offset are known. In other words, it's G + A. 1310b57cec5SDimitry Andric // 1320b57cec5SDimitry Andric // foo@GOT(%ebx) needs to be resolved to a *relative* offset from a GOT to 1330b57cec5SDimitry Andric // foo's GOT entry in the table, because GOT address is not known but foo's 1340b57cec5SDimitry Andric // offset in the table is known. It's G + A - GOT. 1350b57cec5SDimitry Andric // 1360b57cec5SDimitry Andric // It's unfortunate that compilers emit the same relocation for these 1370b57cec5SDimitry Andric // different use cases. In order to distinguish them, we have to read a 1380b57cec5SDimitry Andric // machine instruction. 1390b57cec5SDimitry Andric // 1400b57cec5SDimitry Andric // The following code implements it. We assume that Loc[0] is the first byte 1410b57cec5SDimitry Andric // of a displacement or an immediate field of a valid machine 1420b57cec5SDimitry Andric // instruction. That means a ModRM byte is at Loc[-1]. By taking a look at 1430b57cec5SDimitry Andric // the byte, we can determine whether the instruction uses the operand as an 1440b57cec5SDimitry Andric // absolute address (R_GOT) or a register-relative address (R_GOTPLT). 1450b57cec5SDimitry Andric return (loc[-1] & 0xc7) == 0x5 ? R_GOT : R_GOTPLT; 1460b57cec5SDimitry Andric case R_386_TLS_GOTIE: 1470b57cec5SDimitry Andric return R_GOTPLT; 1480b57cec5SDimitry Andric case R_386_GOTOFF: 1490b57cec5SDimitry Andric return R_GOTPLTREL; 1500b57cec5SDimitry Andric case R_386_TLS_LE: 151*e8d8bef9SDimitry Andric return R_TPREL; 1520b57cec5SDimitry Andric case R_386_TLS_LE_32: 153*e8d8bef9SDimitry Andric return R_TPREL_NEG; 1540b57cec5SDimitry Andric case R_386_NONE: 1550b57cec5SDimitry Andric return R_NONE; 1560b57cec5SDimitry Andric default: 1570b57cec5SDimitry Andric error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + 1580b57cec5SDimitry Andric ") against symbol " + toString(s)); 1590b57cec5SDimitry Andric return R_NONE; 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric 163*e8d8bef9SDimitry Andric RelExpr X86::adjustTlsExpr(RelType type, RelExpr expr) const { 1640b57cec5SDimitry Andric switch (expr) { 1650b57cec5SDimitry Andric default: 1660b57cec5SDimitry Andric return expr; 1670b57cec5SDimitry Andric case R_RELAX_TLS_GD_TO_IE: 1680b57cec5SDimitry Andric return R_RELAX_TLS_GD_TO_IE_GOTPLT; 1690b57cec5SDimitry Andric case R_RELAX_TLS_GD_TO_LE: 1700b57cec5SDimitry Andric return R_RELAX_TLS_GD_TO_LE_NEG; 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric void X86::writeGotPltHeader(uint8_t *buf) const { 1750b57cec5SDimitry Andric write32le(buf, mainPart->dynamic->getVA()); 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric void X86::writeGotPlt(uint8_t *buf, const Symbol &s) const { 1790b57cec5SDimitry Andric // Entries in .got.plt initially points back to the corresponding 1800b57cec5SDimitry Andric // PLT entries with a fixed offset to skip the first instruction. 1810b57cec5SDimitry Andric write32le(buf, s.getPltVA() + 6); 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric void X86::writeIgotPlt(uint8_t *buf, const Symbol &s) const { 1850b57cec5SDimitry Andric // An x86 entry is the address of the ifunc resolver function. 1860b57cec5SDimitry Andric write32le(buf, s.getVA()); 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric RelType X86::getDynRel(RelType type) const { 1900b57cec5SDimitry Andric if (type == R_386_TLS_LE) 1910b57cec5SDimitry Andric return R_386_TLS_TPOFF; 1920b57cec5SDimitry Andric if (type == R_386_TLS_LE_32) 1930b57cec5SDimitry Andric return R_386_TLS_TPOFF32; 1940b57cec5SDimitry Andric return type; 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric void X86::writePltHeader(uint8_t *buf) const { 1980b57cec5SDimitry Andric if (config->isPic) { 1990b57cec5SDimitry Andric const uint8_t v[] = { 2000b57cec5SDimitry Andric 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx) 2010b57cec5SDimitry Andric 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx) 2020b57cec5SDimitry Andric 0x90, 0x90, 0x90, 0x90 // nop 2030b57cec5SDimitry Andric }; 2040b57cec5SDimitry Andric memcpy(buf, v, sizeof(v)); 2050b57cec5SDimitry Andric return; 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric const uint8_t pltData[] = { 2090b57cec5SDimitry Andric 0xff, 0x35, 0, 0, 0, 0, // pushl (GOTPLT+4) 2100b57cec5SDimitry Andric 0xff, 0x25, 0, 0, 0, 0, // jmp *(GOTPLT+8) 2110b57cec5SDimitry Andric 0x90, 0x90, 0x90, 0x90, // nop 2120b57cec5SDimitry Andric }; 2130b57cec5SDimitry Andric memcpy(buf, pltData, sizeof(pltData)); 2140b57cec5SDimitry Andric uint32_t gotPlt = in.gotPlt->getVA(); 2150b57cec5SDimitry Andric write32le(buf + 2, gotPlt + 4); 2160b57cec5SDimitry Andric write32le(buf + 8, gotPlt + 8); 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric 219480093f4SDimitry Andric void X86::writePlt(uint8_t *buf, const Symbol &sym, 220480093f4SDimitry Andric uint64_t pltEntryAddr) const { 221480093f4SDimitry Andric unsigned relOff = in.relaPlt->entsize * sym.pltIndex; 2220b57cec5SDimitry Andric if (config->isPic) { 2230b57cec5SDimitry Andric const uint8_t inst[] = { 2240b57cec5SDimitry Andric 0xff, 0xa3, 0, 0, 0, 0, // jmp *foo@GOT(%ebx) 2250b57cec5SDimitry Andric 0x68, 0, 0, 0, 0, // pushl $reloc_offset 2260b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC 2270b57cec5SDimitry Andric }; 2280b57cec5SDimitry Andric memcpy(buf, inst, sizeof(inst)); 229480093f4SDimitry Andric write32le(buf + 2, sym.getGotPltVA() - in.gotPlt->getVA()); 2300b57cec5SDimitry Andric } else { 2310b57cec5SDimitry Andric const uint8_t inst[] = { 2320b57cec5SDimitry Andric 0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT 2330b57cec5SDimitry Andric 0x68, 0, 0, 0, 0, // pushl $reloc_offset 2340b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC 2350b57cec5SDimitry Andric }; 2360b57cec5SDimitry Andric memcpy(buf, inst, sizeof(inst)); 237480093f4SDimitry Andric write32le(buf + 2, sym.getGotPltVA()); 2380b57cec5SDimitry Andric } 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric write32le(buf + 7, relOff); 241480093f4SDimitry Andric write32le(buf + 12, in.plt->getVA() - pltEntryAddr - 16); 2420b57cec5SDimitry Andric } 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric int64_t X86::getImplicitAddend(const uint8_t *buf, RelType type) const { 2450b57cec5SDimitry Andric switch (type) { 2460b57cec5SDimitry Andric case R_386_8: 2470b57cec5SDimitry Andric case R_386_PC8: 2480b57cec5SDimitry Andric return SignExtend64<8>(*buf); 2490b57cec5SDimitry Andric case R_386_16: 2500b57cec5SDimitry Andric case R_386_PC16: 2510b57cec5SDimitry Andric return SignExtend64<16>(read16le(buf)); 2520b57cec5SDimitry Andric case R_386_32: 2530b57cec5SDimitry Andric case R_386_GOT32: 2540b57cec5SDimitry Andric case R_386_GOT32X: 2550b57cec5SDimitry Andric case R_386_GOTOFF: 2560b57cec5SDimitry Andric case R_386_GOTPC: 2570b57cec5SDimitry Andric case R_386_PC32: 2580b57cec5SDimitry Andric case R_386_PLT32: 2590b57cec5SDimitry Andric case R_386_TLS_LDO_32: 2600b57cec5SDimitry Andric case R_386_TLS_LE: 2610b57cec5SDimitry Andric return SignExtend64<32>(read32le(buf)); 2620b57cec5SDimitry Andric default: 2630b57cec5SDimitry Andric return 0; 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric 2675ffd83dbSDimitry Andric void X86::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { 2685ffd83dbSDimitry Andric switch (rel.type) { 2690b57cec5SDimitry Andric case R_386_8: 2700b57cec5SDimitry Andric // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are 2710b57cec5SDimitry Andric // being used for some 16-bit programs such as boot loaders, so 2720b57cec5SDimitry Andric // we want to support them. 2735ffd83dbSDimitry Andric checkIntUInt(loc, val, 8, rel); 2740b57cec5SDimitry Andric *loc = val; 2750b57cec5SDimitry Andric break; 2760b57cec5SDimitry Andric case R_386_PC8: 2775ffd83dbSDimitry Andric checkInt(loc, val, 8, rel); 2780b57cec5SDimitry Andric *loc = val; 2790b57cec5SDimitry Andric break; 2800b57cec5SDimitry Andric case R_386_16: 2815ffd83dbSDimitry Andric checkIntUInt(loc, val, 16, rel); 2820b57cec5SDimitry Andric write16le(loc, val); 2830b57cec5SDimitry Andric break; 2840b57cec5SDimitry Andric case R_386_PC16: 2850b57cec5SDimitry Andric // R_386_PC16 is normally used with 16 bit code. In that situation 2860b57cec5SDimitry Andric // the PC is 16 bits, just like the addend. This means that it can 2870b57cec5SDimitry Andric // point from any 16 bit address to any other if the possibility 2880b57cec5SDimitry Andric // of wrapping is included. 2890b57cec5SDimitry Andric // The only restriction we have to check then is that the destination 2900b57cec5SDimitry Andric // address fits in 16 bits. That is impossible to do here. The problem is 2910b57cec5SDimitry Andric // that we are passed the final value, which already had the 2920b57cec5SDimitry Andric // current location subtracted from it. 2930b57cec5SDimitry Andric // We just check that Val fits in 17 bits. This misses some cases, but 2940b57cec5SDimitry Andric // should have no false positives. 2955ffd83dbSDimitry Andric checkInt(loc, val, 17, rel); 2960b57cec5SDimitry Andric write16le(loc, val); 2970b57cec5SDimitry Andric break; 2980b57cec5SDimitry Andric case R_386_32: 2990b57cec5SDimitry Andric case R_386_GOT32: 3000b57cec5SDimitry Andric case R_386_GOT32X: 3010b57cec5SDimitry Andric case R_386_GOTOFF: 3020b57cec5SDimitry Andric case R_386_GOTPC: 3030b57cec5SDimitry Andric case R_386_PC32: 3040b57cec5SDimitry Andric case R_386_PLT32: 3050b57cec5SDimitry Andric case R_386_RELATIVE: 3060b57cec5SDimitry Andric case R_386_TLS_DTPMOD32: 3070b57cec5SDimitry Andric case R_386_TLS_DTPOFF32: 3080b57cec5SDimitry Andric case R_386_TLS_GD: 3090b57cec5SDimitry Andric case R_386_TLS_GOTIE: 3100b57cec5SDimitry Andric case R_386_TLS_IE: 3110b57cec5SDimitry Andric case R_386_TLS_LDM: 3120b57cec5SDimitry Andric case R_386_TLS_LDO_32: 3130b57cec5SDimitry Andric case R_386_TLS_LE: 3140b57cec5SDimitry Andric case R_386_TLS_LE_32: 3150b57cec5SDimitry Andric case R_386_TLS_TPOFF: 3160b57cec5SDimitry Andric case R_386_TLS_TPOFF32: 3175ffd83dbSDimitry Andric checkInt(loc, val, 32, rel); 3180b57cec5SDimitry Andric write32le(loc, val); 3190b57cec5SDimitry Andric break; 3200b57cec5SDimitry Andric default: 3210b57cec5SDimitry Andric llvm_unreachable("unknown relocation"); 3220b57cec5SDimitry Andric } 3230b57cec5SDimitry Andric } 3240b57cec5SDimitry Andric 3255ffd83dbSDimitry Andric void X86::relaxTlsGdToLe(uint8_t *loc, const Relocation &, uint64_t val) const { 3260b57cec5SDimitry Andric // Convert 3270b57cec5SDimitry Andric // leal x@tlsgd(, %ebx, 1), 3280b57cec5SDimitry Andric // call __tls_get_addr@plt 3290b57cec5SDimitry Andric // to 3300b57cec5SDimitry Andric // movl %gs:0,%eax 3310b57cec5SDimitry Andric // subl $x@ntpoff,%eax 3320b57cec5SDimitry Andric const uint8_t inst[] = { 3330b57cec5SDimitry Andric 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 3340b57cec5SDimitry Andric 0x81, 0xe8, 0, 0, 0, 0, // subl Val(%ebx), %eax 3350b57cec5SDimitry Andric }; 3360b57cec5SDimitry Andric memcpy(loc - 3, inst, sizeof(inst)); 3370b57cec5SDimitry Andric write32le(loc + 5, val); 3380b57cec5SDimitry Andric } 3390b57cec5SDimitry Andric 3405ffd83dbSDimitry Andric void X86::relaxTlsGdToIe(uint8_t *loc, const Relocation &, uint64_t val) const { 3410b57cec5SDimitry Andric // Convert 3420b57cec5SDimitry Andric // leal x@tlsgd(, %ebx, 1), 3430b57cec5SDimitry Andric // call __tls_get_addr@plt 3440b57cec5SDimitry Andric // to 3450b57cec5SDimitry Andric // movl %gs:0, %eax 3460b57cec5SDimitry Andric // addl x@gotntpoff(%ebx), %eax 3470b57cec5SDimitry Andric const uint8_t inst[] = { 3480b57cec5SDimitry Andric 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 3490b57cec5SDimitry Andric 0x03, 0x83, 0, 0, 0, 0, // addl Val(%ebx), %eax 3500b57cec5SDimitry Andric }; 3510b57cec5SDimitry Andric memcpy(loc - 3, inst, sizeof(inst)); 3520b57cec5SDimitry Andric write32le(loc + 5, val); 3530b57cec5SDimitry Andric } 3540b57cec5SDimitry Andric 3550b57cec5SDimitry Andric // In some conditions, relocations can be optimized to avoid using GOT. 3560b57cec5SDimitry Andric // This function does that for Initial Exec to Local Exec case. 3575ffd83dbSDimitry Andric void X86::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, 3585ffd83dbSDimitry Andric uint64_t val) const { 3590b57cec5SDimitry Andric // Ulrich's document section 6.2 says that @gotntpoff can 3600b57cec5SDimitry Andric // be used with MOVL or ADDL instructions. 3610b57cec5SDimitry Andric // @indntpoff is similar to @gotntpoff, but for use in 3620b57cec5SDimitry Andric // position dependent code. 3630b57cec5SDimitry Andric uint8_t reg = (loc[-1] >> 3) & 7; 3640b57cec5SDimitry Andric 3655ffd83dbSDimitry Andric if (rel.type == R_386_TLS_IE) { 3660b57cec5SDimitry Andric if (loc[-1] == 0xa1) { 3670b57cec5SDimitry Andric // "movl foo@indntpoff,%eax" -> "movl $foo,%eax" 3680b57cec5SDimitry Andric // This case is different from the generic case below because 3690b57cec5SDimitry Andric // this is a 5 byte instruction while below is 6 bytes. 3700b57cec5SDimitry Andric loc[-1] = 0xb8; 3710b57cec5SDimitry Andric } else if (loc[-2] == 0x8b) { 3720b57cec5SDimitry Andric // "movl foo@indntpoff,%reg" -> "movl $foo,%reg" 3730b57cec5SDimitry Andric loc[-2] = 0xc7; 3740b57cec5SDimitry Andric loc[-1] = 0xc0 | reg; 3750b57cec5SDimitry Andric } else { 3760b57cec5SDimitry Andric // "addl foo@indntpoff,%reg" -> "addl $foo,%reg" 3770b57cec5SDimitry Andric loc[-2] = 0x81; 3780b57cec5SDimitry Andric loc[-1] = 0xc0 | reg; 3790b57cec5SDimitry Andric } 3800b57cec5SDimitry Andric } else { 3815ffd83dbSDimitry Andric assert(rel.type == R_386_TLS_GOTIE); 3820b57cec5SDimitry Andric if (loc[-2] == 0x8b) { 3830b57cec5SDimitry Andric // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg" 3840b57cec5SDimitry Andric loc[-2] = 0xc7; 3850b57cec5SDimitry Andric loc[-1] = 0xc0 | reg; 3860b57cec5SDimitry Andric } else { 3870b57cec5SDimitry Andric // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg" 3880b57cec5SDimitry Andric loc[-2] = 0x8d; 3890b57cec5SDimitry Andric loc[-1] = 0x80 | (reg << 3) | reg; 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric } 3920b57cec5SDimitry Andric write32le(loc, val); 3930b57cec5SDimitry Andric } 3940b57cec5SDimitry Andric 3955ffd83dbSDimitry Andric void X86::relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, 3965ffd83dbSDimitry Andric uint64_t val) const { 3975ffd83dbSDimitry Andric if (rel.type == R_386_TLS_LDO_32) { 3980b57cec5SDimitry Andric write32le(loc, val); 3990b57cec5SDimitry Andric return; 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric // Convert 4030b57cec5SDimitry Andric // leal foo(%reg),%eax 4040b57cec5SDimitry Andric // call ___tls_get_addr 4050b57cec5SDimitry Andric // to 4060b57cec5SDimitry Andric // movl %gs:0,%eax 4070b57cec5SDimitry Andric // nop 4080b57cec5SDimitry Andric // leal 0(%esi,1),%esi 4090b57cec5SDimitry Andric const uint8_t inst[] = { 4100b57cec5SDimitry Andric 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax 4110b57cec5SDimitry Andric 0x90, // nop 4120b57cec5SDimitry Andric 0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi 4130b57cec5SDimitry Andric }; 4140b57cec5SDimitry Andric memcpy(loc - 2, inst, sizeof(inst)); 4150b57cec5SDimitry Andric } 4160b57cec5SDimitry Andric 417480093f4SDimitry Andric // If Intel Indirect Branch Tracking is enabled, we have to emit special PLT 418480093f4SDimitry Andric // entries containing endbr32 instructions. A PLT entry will be split into two 419480093f4SDimitry Andric // parts, one in .plt.sec (writePlt), and the other in .plt (writeIBTPlt). 420480093f4SDimitry Andric namespace { 421480093f4SDimitry Andric class IntelIBT : public X86 { 422480093f4SDimitry Andric public: 423480093f4SDimitry Andric IntelIBT(); 424480093f4SDimitry Andric void writeGotPlt(uint8_t *buf, const Symbol &s) const override; 425480093f4SDimitry Andric void writePlt(uint8_t *buf, const Symbol &sym, 426480093f4SDimitry Andric uint64_t pltEntryAddr) const override; 427480093f4SDimitry Andric void writeIBTPlt(uint8_t *buf, size_t numEntries) const override; 428480093f4SDimitry Andric 429480093f4SDimitry Andric static const unsigned IBTPltHeaderSize = 16; 430480093f4SDimitry Andric }; 431480093f4SDimitry Andric } // namespace 432480093f4SDimitry Andric 433480093f4SDimitry Andric IntelIBT::IntelIBT() { pltHeaderSize = 0; } 434480093f4SDimitry Andric 435480093f4SDimitry Andric void IntelIBT::writeGotPlt(uint8_t *buf, const Symbol &s) const { 436480093f4SDimitry Andric uint64_t va = 437480093f4SDimitry Andric in.ibtPlt->getVA() + IBTPltHeaderSize + s.pltIndex * pltEntrySize; 438480093f4SDimitry Andric write32le(buf, va); 439480093f4SDimitry Andric } 440480093f4SDimitry Andric 441480093f4SDimitry Andric void IntelIBT::writePlt(uint8_t *buf, const Symbol &sym, 442480093f4SDimitry Andric uint64_t /*pltEntryAddr*/) const { 443480093f4SDimitry Andric if (config->isPic) { 444480093f4SDimitry Andric const uint8_t inst[] = { 445480093f4SDimitry Andric 0xf3, 0x0f, 0x1e, 0xfb, // endbr32 446480093f4SDimitry Andric 0xff, 0xa3, 0, 0, 0, 0, // jmp *name@GOT(%ebx) 447480093f4SDimitry Andric 0x66, 0x0f, 0x1f, 0x44, 0, 0, // nop 448480093f4SDimitry Andric }; 449480093f4SDimitry Andric memcpy(buf, inst, sizeof(inst)); 450480093f4SDimitry Andric write32le(buf + 6, sym.getGotPltVA() - in.gotPlt->getVA()); 451480093f4SDimitry Andric return; 452480093f4SDimitry Andric } 453480093f4SDimitry Andric 454480093f4SDimitry Andric const uint8_t inst[] = { 455480093f4SDimitry Andric 0xf3, 0x0f, 0x1e, 0xfb, // endbr32 456480093f4SDimitry Andric 0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT 457480093f4SDimitry Andric 0x66, 0x0f, 0x1f, 0x44, 0, 0, // nop 458480093f4SDimitry Andric }; 459480093f4SDimitry Andric memcpy(buf, inst, sizeof(inst)); 460480093f4SDimitry Andric write32le(buf + 6, sym.getGotPltVA()); 461480093f4SDimitry Andric } 462480093f4SDimitry Andric 463480093f4SDimitry Andric void IntelIBT::writeIBTPlt(uint8_t *buf, size_t numEntries) const { 464480093f4SDimitry Andric writePltHeader(buf); 465480093f4SDimitry Andric buf += IBTPltHeaderSize; 466480093f4SDimitry Andric 467480093f4SDimitry Andric const uint8_t inst[] = { 468480093f4SDimitry Andric 0xf3, 0x0f, 0x1e, 0xfb, // endbr32 469480093f4SDimitry Andric 0x68, 0, 0, 0, 0, // pushl $reloc_offset 470480093f4SDimitry Andric 0xe9, 0, 0, 0, 0, // jmpq .PLT0@PC 471480093f4SDimitry Andric 0x66, 0x90, // nop 472480093f4SDimitry Andric }; 473480093f4SDimitry Andric 474480093f4SDimitry Andric for (size_t i = 0; i < numEntries; ++i) { 475480093f4SDimitry Andric memcpy(buf, inst, sizeof(inst)); 476480093f4SDimitry Andric write32le(buf + 5, i * sizeof(object::ELF32LE::Rel)); 477480093f4SDimitry Andric write32le(buf + 10, -pltHeaderSize - sizeof(inst) * i - 30); 478480093f4SDimitry Andric buf += sizeof(inst); 479480093f4SDimitry Andric } 480480093f4SDimitry Andric } 481480093f4SDimitry Andric 4820b57cec5SDimitry Andric namespace { 4830b57cec5SDimitry Andric class RetpolinePic : public X86 { 4840b57cec5SDimitry Andric public: 4850b57cec5SDimitry Andric RetpolinePic(); 4860b57cec5SDimitry Andric void writeGotPlt(uint8_t *buf, const Symbol &s) const override; 4870b57cec5SDimitry Andric void writePltHeader(uint8_t *buf) const override; 488480093f4SDimitry Andric void writePlt(uint8_t *buf, const Symbol &sym, 489480093f4SDimitry Andric uint64_t pltEntryAddr) const override; 4900b57cec5SDimitry Andric }; 4910b57cec5SDimitry Andric 4920b57cec5SDimitry Andric class RetpolineNoPic : public X86 { 4930b57cec5SDimitry Andric public: 4940b57cec5SDimitry Andric RetpolineNoPic(); 4950b57cec5SDimitry Andric void writeGotPlt(uint8_t *buf, const Symbol &s) const override; 4960b57cec5SDimitry Andric void writePltHeader(uint8_t *buf) const override; 497480093f4SDimitry Andric void writePlt(uint8_t *buf, const Symbol &sym, 498480093f4SDimitry Andric uint64_t pltEntryAddr) const override; 4990b57cec5SDimitry Andric }; 5000b57cec5SDimitry Andric } // namespace 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric RetpolinePic::RetpolinePic() { 5030b57cec5SDimitry Andric pltHeaderSize = 48; 5040b57cec5SDimitry Andric pltEntrySize = 32; 505480093f4SDimitry Andric ipltEntrySize = 32; 5060b57cec5SDimitry Andric } 5070b57cec5SDimitry Andric 5080b57cec5SDimitry Andric void RetpolinePic::writeGotPlt(uint8_t *buf, const Symbol &s) const { 5090b57cec5SDimitry Andric write32le(buf, s.getPltVA() + 17); 5100b57cec5SDimitry Andric } 5110b57cec5SDimitry Andric 5120b57cec5SDimitry Andric void RetpolinePic::writePltHeader(uint8_t *buf) const { 5130b57cec5SDimitry Andric const uint8_t insn[] = { 5140b57cec5SDimitry Andric 0xff, 0xb3, 4, 0, 0, 0, // 0: pushl 4(%ebx) 5150b57cec5SDimitry Andric 0x50, // 6: pushl %eax 5160b57cec5SDimitry Andric 0x8b, 0x83, 8, 0, 0, 0, // 7: mov 8(%ebx), %eax 5170b57cec5SDimitry Andric 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: call next 5180b57cec5SDimitry Andric 0xf3, 0x90, // 12: loop: pause 5190b57cec5SDimitry Andric 0x0f, 0xae, 0xe8, // 14: lfence 5200b57cec5SDimitry Andric 0xeb, 0xf9, // 17: jmp loop 5210b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 5220b57cec5SDimitry Andric 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) 5230b57cec5SDimitry Andric 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx 5240b57cec5SDimitry Andric 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) 5250b57cec5SDimitry Andric 0x89, 0xc8, // 2b: mov %ecx, %eax 5260b57cec5SDimitry Andric 0x59, // 2d: pop %ecx 5270b57cec5SDimitry Andric 0xc3, // 2e: ret 5280b57cec5SDimitry Andric 0xcc, // 2f: int3; padding 5290b57cec5SDimitry Andric }; 5300b57cec5SDimitry Andric memcpy(buf, insn, sizeof(insn)); 5310b57cec5SDimitry Andric } 5320b57cec5SDimitry Andric 533480093f4SDimitry Andric void RetpolinePic::writePlt(uint8_t *buf, const Symbol &sym, 534480093f4SDimitry Andric uint64_t pltEntryAddr) const { 535480093f4SDimitry Andric unsigned relOff = in.relaPlt->entsize * sym.pltIndex; 5360b57cec5SDimitry Andric const uint8_t insn[] = { 5370b57cec5SDimitry Andric 0x50, // pushl %eax 5380b57cec5SDimitry Andric 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax 5390b57cec5SDimitry Andric 0xe8, 0, 0, 0, 0, // call plt+0x20 5400b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // jmp plt+0x12 5410b57cec5SDimitry Andric 0x68, 0, 0, 0, 0, // pushl $reloc_offset 5420b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // jmp plt+0 5430b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding 5440b57cec5SDimitry Andric }; 5450b57cec5SDimitry Andric memcpy(buf, insn, sizeof(insn)); 5460b57cec5SDimitry Andric 5470b57cec5SDimitry Andric uint32_t ebx = in.gotPlt->getVA(); 548480093f4SDimitry Andric unsigned off = pltEntryAddr - in.plt->getVA(); 549480093f4SDimitry Andric write32le(buf + 3, sym.getGotPltVA() - ebx); 5500b57cec5SDimitry Andric write32le(buf + 8, -off - 12 + 32); 5510b57cec5SDimitry Andric write32le(buf + 13, -off - 17 + 18); 5520b57cec5SDimitry Andric write32le(buf + 18, relOff); 5530b57cec5SDimitry Andric write32le(buf + 23, -off - 27); 5540b57cec5SDimitry Andric } 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric RetpolineNoPic::RetpolineNoPic() { 5570b57cec5SDimitry Andric pltHeaderSize = 48; 5580b57cec5SDimitry Andric pltEntrySize = 32; 559480093f4SDimitry Andric ipltEntrySize = 32; 5600b57cec5SDimitry Andric } 5610b57cec5SDimitry Andric 5620b57cec5SDimitry Andric void RetpolineNoPic::writeGotPlt(uint8_t *buf, const Symbol &s) const { 5630b57cec5SDimitry Andric write32le(buf, s.getPltVA() + 16); 5640b57cec5SDimitry Andric } 5650b57cec5SDimitry Andric 5660b57cec5SDimitry Andric void RetpolineNoPic::writePltHeader(uint8_t *buf) const { 5670b57cec5SDimitry Andric const uint8_t insn[] = { 5680b57cec5SDimitry Andric 0xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+4 5690b57cec5SDimitry Andric 0x50, // 6: pushl %eax 5700b57cec5SDimitry Andric 0xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax 5710b57cec5SDimitry Andric 0xe8, 0x0f, 0x00, 0x00, 0x00, // c: call next 5720b57cec5SDimitry Andric 0xf3, 0x90, // 11: loop: pause 5730b57cec5SDimitry Andric 0x0f, 0xae, 0xe8, // 13: lfence 5740b57cec5SDimitry Andric 0xeb, 0xf9, // 16: jmp loop 5750b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 18: int3 5760b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, // 1f: int3; .align 16 5770b57cec5SDimitry Andric 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) 5780b57cec5SDimitry Andric 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx 5790b57cec5SDimitry Andric 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) 5800b57cec5SDimitry Andric 0x89, 0xc8, // 2b: mov %ecx, %eax 5810b57cec5SDimitry Andric 0x59, // 2d: pop %ecx 5820b57cec5SDimitry Andric 0xc3, // 2e: ret 5830b57cec5SDimitry Andric 0xcc, // 2f: int3; padding 5840b57cec5SDimitry Andric }; 5850b57cec5SDimitry Andric memcpy(buf, insn, sizeof(insn)); 5860b57cec5SDimitry Andric 5870b57cec5SDimitry Andric uint32_t gotPlt = in.gotPlt->getVA(); 5880b57cec5SDimitry Andric write32le(buf + 2, gotPlt + 4); 5890b57cec5SDimitry Andric write32le(buf + 8, gotPlt + 8); 5900b57cec5SDimitry Andric } 5910b57cec5SDimitry Andric 592480093f4SDimitry Andric void RetpolineNoPic::writePlt(uint8_t *buf, const Symbol &sym, 593480093f4SDimitry Andric uint64_t pltEntryAddr) const { 594480093f4SDimitry Andric unsigned relOff = in.relaPlt->entsize * sym.pltIndex; 5950b57cec5SDimitry Andric const uint8_t insn[] = { 5960b57cec5SDimitry Andric 0x50, // 0: pushl %eax 5970b57cec5SDimitry Andric 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax 5980b57cec5SDimitry Andric 0xe8, 0, 0, 0, 0, // 6: call plt+0x20 5990b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11 6000b57cec5SDimitry Andric 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset 6010b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // 15: jmp plt+0 6020b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding 6030b57cec5SDimitry Andric 0xcc, // 1f: int3; padding 6040b57cec5SDimitry Andric }; 6050b57cec5SDimitry Andric memcpy(buf, insn, sizeof(insn)); 6060b57cec5SDimitry Andric 607480093f4SDimitry Andric unsigned off = pltEntryAddr - in.plt->getVA(); 608480093f4SDimitry Andric write32le(buf + 2, sym.getGotPltVA()); 6090b57cec5SDimitry Andric write32le(buf + 7, -off - 11 + 32); 6100b57cec5SDimitry Andric write32le(buf + 12, -off - 16 + 17); 6110b57cec5SDimitry Andric write32le(buf + 17, relOff); 6120b57cec5SDimitry Andric write32le(buf + 22, -off - 26); 6130b57cec5SDimitry Andric } 6140b57cec5SDimitry Andric 6155ffd83dbSDimitry Andric TargetInfo *elf::getX86TargetInfo() { 6160b57cec5SDimitry Andric if (config->zRetpolineplt) { 6170b57cec5SDimitry Andric if (config->isPic) { 6180b57cec5SDimitry Andric static RetpolinePic t; 6190b57cec5SDimitry Andric return &t; 6200b57cec5SDimitry Andric } 6210b57cec5SDimitry Andric static RetpolineNoPic t; 6220b57cec5SDimitry Andric return &t; 6230b57cec5SDimitry Andric } 6240b57cec5SDimitry Andric 625480093f4SDimitry Andric if (config->andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT) { 626480093f4SDimitry Andric static IntelIBT t; 627480093f4SDimitry Andric return &t; 628480093f4SDimitry Andric } 629480093f4SDimitry Andric 6300b57cec5SDimitry Andric static X86 t; 6310b57cec5SDimitry Andric return &t; 6320b57cec5SDimitry Andric } 633