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; 1985868e8aSDimitry Andric 2085868e8aSDimitry Andric namespace lld { 2185868e8aSDimitry Andric namespace elf { 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric namespace { 240b57cec5SDimitry Andric class X86 : public TargetInfo { 250b57cec5SDimitry Andric public: 260b57cec5SDimitry Andric X86(); 270b57cec5SDimitry Andric int getTlsGdRelaxSkip(RelType type) const override; 280b57cec5SDimitry Andric RelExpr getRelExpr(RelType type, const Symbol &s, 290b57cec5SDimitry Andric const uint8_t *loc) const override; 300b57cec5SDimitry Andric int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; 310b57cec5SDimitry Andric void writeGotPltHeader(uint8_t *buf) const override; 320b57cec5SDimitry Andric RelType getDynRel(RelType type) const override; 330b57cec5SDimitry Andric void writeGotPlt(uint8_t *buf, const Symbol &s) const override; 340b57cec5SDimitry Andric void writeIgotPlt(uint8_t *buf, const Symbol &s) const override; 350b57cec5SDimitry Andric void writePltHeader(uint8_t *buf) const override; 36*480093f4SDimitry Andric void writePlt(uint8_t *buf, const Symbol &sym, 37*480093f4SDimitry Andric uint64_t pltEntryAddr) const override; 380b57cec5SDimitry Andric void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric RelExpr adjustRelaxExpr(RelType type, const uint8_t *data, 410b57cec5SDimitry Andric RelExpr expr) const override; 420b57cec5SDimitry Andric void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override; 430b57cec5SDimitry Andric void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override; 440b57cec5SDimitry Andric void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override; 450b57cec5SDimitry Andric void relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const override; 460b57cec5SDimitry Andric }; 470b57cec5SDimitry Andric } // namespace 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric X86::X86() { 500b57cec5SDimitry Andric copyRel = R_386_COPY; 510b57cec5SDimitry Andric gotRel = R_386_GLOB_DAT; 520b57cec5SDimitry Andric noneRel = R_386_NONE; 530b57cec5SDimitry Andric pltRel = R_386_JUMP_SLOT; 540b57cec5SDimitry Andric iRelativeRel = R_386_IRELATIVE; 550b57cec5SDimitry Andric relativeRel = R_386_RELATIVE; 560b57cec5SDimitry Andric symbolicRel = R_386_32; 570b57cec5SDimitry Andric tlsGotRel = R_386_TLS_TPOFF; 580b57cec5SDimitry Andric tlsModuleIndexRel = R_386_TLS_DTPMOD32; 590b57cec5SDimitry Andric tlsOffsetRel = R_386_TLS_DTPOFF32; 600b57cec5SDimitry Andric pltHeaderSize = 16; 61*480093f4SDimitry Andric pltEntrySize = 16; 62*480093f4SDimitry Andric ipltEntrySize = 16; 630b57cec5SDimitry Andric trapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric // Align to the non-PAE large page size (known as a superpage or huge page). 660b57cec5SDimitry Andric // FreeBSD automatically promotes large, superpage-aligned allocations. 670b57cec5SDimitry Andric defaultImageBase = 0x400000; 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric int X86::getTlsGdRelaxSkip(RelType type) const { 710b57cec5SDimitry Andric return 2; 720b57cec5SDimitry Andric } 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric RelExpr X86::getRelExpr(RelType type, const Symbol &s, 750b57cec5SDimitry Andric const uint8_t *loc) const { 760b57cec5SDimitry Andric // There are 4 different TLS variable models with varying degrees of 770b57cec5SDimitry Andric // flexibility and performance. LocalExec and InitialExec models are fast but 780b57cec5SDimitry Andric // less-flexible models. If they are in use, we set DF_STATIC_TLS flag in the 790b57cec5SDimitry Andric // dynamic section to let runtime know about that. 800b57cec5SDimitry Andric if (type == R_386_TLS_LE || type == R_386_TLS_LE_32 || type == R_386_TLS_IE || 810b57cec5SDimitry Andric type == R_386_TLS_GOTIE) 820b57cec5SDimitry Andric config->hasStaticTlsModel = 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 119*480093f4SDimitry 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; 1430b57cec5SDimitry Andric case R_386_TLS_GOTIE: 1440b57cec5SDimitry Andric return R_GOTPLT; 1450b57cec5SDimitry Andric case R_386_GOTOFF: 1460b57cec5SDimitry Andric return R_GOTPLTREL; 1470b57cec5SDimitry Andric case R_386_TLS_LE: 1480b57cec5SDimitry Andric return R_TLS; 1490b57cec5SDimitry Andric case R_386_TLS_LE_32: 1500b57cec5SDimitry Andric return R_NEG_TLS; 1510b57cec5SDimitry Andric case R_386_NONE: 1520b57cec5SDimitry Andric return R_NONE; 1530b57cec5SDimitry Andric default: 1540b57cec5SDimitry Andric error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + 1550b57cec5SDimitry Andric ") against symbol " + toString(s)); 1560b57cec5SDimitry Andric return R_NONE; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric RelExpr X86::adjustRelaxExpr(RelType type, const uint8_t *data, 1610b57cec5SDimitry Andric RelExpr expr) const { 1620b57cec5SDimitry Andric switch (expr) { 1630b57cec5SDimitry Andric default: 1640b57cec5SDimitry Andric return expr; 1650b57cec5SDimitry Andric case R_RELAX_TLS_GD_TO_IE: 1660b57cec5SDimitry Andric return R_RELAX_TLS_GD_TO_IE_GOTPLT; 1670b57cec5SDimitry Andric case R_RELAX_TLS_GD_TO_LE: 1680b57cec5SDimitry Andric return R_RELAX_TLS_GD_TO_LE_NEG; 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric void X86::writeGotPltHeader(uint8_t *buf) const { 1730b57cec5SDimitry Andric write32le(buf, mainPart->dynamic->getVA()); 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric void X86::writeGotPlt(uint8_t *buf, const Symbol &s) const { 1770b57cec5SDimitry Andric // Entries in .got.plt initially points back to the corresponding 1780b57cec5SDimitry Andric // PLT entries with a fixed offset to skip the first instruction. 1790b57cec5SDimitry Andric write32le(buf, s.getPltVA() + 6); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric void X86::writeIgotPlt(uint8_t *buf, const Symbol &s) const { 1830b57cec5SDimitry Andric // An x86 entry is the address of the ifunc resolver function. 1840b57cec5SDimitry Andric write32le(buf, s.getVA()); 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric RelType X86::getDynRel(RelType type) const { 1880b57cec5SDimitry Andric if (type == R_386_TLS_LE) 1890b57cec5SDimitry Andric return R_386_TLS_TPOFF; 1900b57cec5SDimitry Andric if (type == R_386_TLS_LE_32) 1910b57cec5SDimitry Andric return R_386_TLS_TPOFF32; 1920b57cec5SDimitry Andric return type; 1930b57cec5SDimitry Andric } 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric void X86::writePltHeader(uint8_t *buf) const { 1960b57cec5SDimitry Andric if (config->isPic) { 1970b57cec5SDimitry Andric const uint8_t v[] = { 1980b57cec5SDimitry Andric 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx) 1990b57cec5SDimitry Andric 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx) 2000b57cec5SDimitry Andric 0x90, 0x90, 0x90, 0x90 // nop 2010b57cec5SDimitry Andric }; 2020b57cec5SDimitry Andric memcpy(buf, v, sizeof(v)); 2030b57cec5SDimitry Andric return; 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric const uint8_t pltData[] = { 2070b57cec5SDimitry Andric 0xff, 0x35, 0, 0, 0, 0, // pushl (GOTPLT+4) 2080b57cec5SDimitry Andric 0xff, 0x25, 0, 0, 0, 0, // jmp *(GOTPLT+8) 2090b57cec5SDimitry Andric 0x90, 0x90, 0x90, 0x90, // nop 2100b57cec5SDimitry Andric }; 2110b57cec5SDimitry Andric memcpy(buf, pltData, sizeof(pltData)); 2120b57cec5SDimitry Andric uint32_t gotPlt = in.gotPlt->getVA(); 2130b57cec5SDimitry Andric write32le(buf + 2, gotPlt + 4); 2140b57cec5SDimitry Andric write32le(buf + 8, gotPlt + 8); 2150b57cec5SDimitry Andric } 2160b57cec5SDimitry Andric 217*480093f4SDimitry Andric void X86::writePlt(uint8_t *buf, const Symbol &sym, 218*480093f4SDimitry Andric uint64_t pltEntryAddr) const { 219*480093f4SDimitry Andric unsigned relOff = in.relaPlt->entsize * sym.pltIndex; 2200b57cec5SDimitry Andric if (config->isPic) { 2210b57cec5SDimitry Andric const uint8_t inst[] = { 2220b57cec5SDimitry Andric 0xff, 0xa3, 0, 0, 0, 0, // jmp *foo@GOT(%ebx) 2230b57cec5SDimitry Andric 0x68, 0, 0, 0, 0, // pushl $reloc_offset 2240b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC 2250b57cec5SDimitry Andric }; 2260b57cec5SDimitry Andric memcpy(buf, inst, sizeof(inst)); 227*480093f4SDimitry Andric write32le(buf + 2, sym.getGotPltVA() - in.gotPlt->getVA()); 2280b57cec5SDimitry Andric } else { 2290b57cec5SDimitry Andric const uint8_t inst[] = { 2300b57cec5SDimitry Andric 0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT 2310b57cec5SDimitry Andric 0x68, 0, 0, 0, 0, // pushl $reloc_offset 2320b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // jmp .PLT0@PC 2330b57cec5SDimitry Andric }; 2340b57cec5SDimitry Andric memcpy(buf, inst, sizeof(inst)); 235*480093f4SDimitry Andric write32le(buf + 2, sym.getGotPltVA()); 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric write32le(buf + 7, relOff); 239*480093f4SDimitry Andric write32le(buf + 12, in.plt->getVA() - pltEntryAddr - 16); 2400b57cec5SDimitry Andric } 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric int64_t X86::getImplicitAddend(const uint8_t *buf, RelType type) const { 2430b57cec5SDimitry Andric switch (type) { 2440b57cec5SDimitry Andric case R_386_8: 2450b57cec5SDimitry Andric case R_386_PC8: 2460b57cec5SDimitry Andric return SignExtend64<8>(*buf); 2470b57cec5SDimitry Andric case R_386_16: 2480b57cec5SDimitry Andric case R_386_PC16: 2490b57cec5SDimitry Andric return SignExtend64<16>(read16le(buf)); 2500b57cec5SDimitry Andric case R_386_32: 2510b57cec5SDimitry Andric case R_386_GOT32: 2520b57cec5SDimitry Andric case R_386_GOT32X: 2530b57cec5SDimitry Andric case R_386_GOTOFF: 2540b57cec5SDimitry Andric case R_386_GOTPC: 2550b57cec5SDimitry Andric case R_386_PC32: 2560b57cec5SDimitry Andric case R_386_PLT32: 2570b57cec5SDimitry Andric case R_386_TLS_LDO_32: 2580b57cec5SDimitry Andric case R_386_TLS_LE: 2590b57cec5SDimitry Andric return SignExtend64<32>(read32le(buf)); 2600b57cec5SDimitry Andric default: 2610b57cec5SDimitry Andric return 0; 2620b57cec5SDimitry Andric } 2630b57cec5SDimitry Andric } 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric void X86::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { 2660b57cec5SDimitry Andric switch (type) { 2670b57cec5SDimitry Andric case R_386_8: 2680b57cec5SDimitry Andric // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are 2690b57cec5SDimitry Andric // being used for some 16-bit programs such as boot loaders, so 2700b57cec5SDimitry Andric // we want to support them. 2710b57cec5SDimitry Andric checkIntUInt(loc, val, 8, type); 2720b57cec5SDimitry Andric *loc = val; 2730b57cec5SDimitry Andric break; 2740b57cec5SDimitry Andric case R_386_PC8: 2750b57cec5SDimitry Andric checkInt(loc, val, 8, type); 2760b57cec5SDimitry Andric *loc = val; 2770b57cec5SDimitry Andric break; 2780b57cec5SDimitry Andric case R_386_16: 2790b57cec5SDimitry Andric checkIntUInt(loc, val, 16, type); 2800b57cec5SDimitry Andric write16le(loc, val); 2810b57cec5SDimitry Andric break; 2820b57cec5SDimitry Andric case R_386_PC16: 2830b57cec5SDimitry Andric // R_386_PC16 is normally used with 16 bit code. In that situation 2840b57cec5SDimitry Andric // the PC is 16 bits, just like the addend. This means that it can 2850b57cec5SDimitry Andric // point from any 16 bit address to any other if the possibility 2860b57cec5SDimitry Andric // of wrapping is included. 2870b57cec5SDimitry Andric // The only restriction we have to check then is that the destination 2880b57cec5SDimitry Andric // address fits in 16 bits. That is impossible to do here. The problem is 2890b57cec5SDimitry Andric // that we are passed the final value, which already had the 2900b57cec5SDimitry Andric // current location subtracted from it. 2910b57cec5SDimitry Andric // We just check that Val fits in 17 bits. This misses some cases, but 2920b57cec5SDimitry Andric // should have no false positives. 2930b57cec5SDimitry Andric checkInt(loc, val, 17, type); 2940b57cec5SDimitry Andric write16le(loc, val); 2950b57cec5SDimitry Andric break; 2960b57cec5SDimitry Andric case R_386_32: 2970b57cec5SDimitry Andric case R_386_GOT32: 2980b57cec5SDimitry Andric case R_386_GOT32X: 2990b57cec5SDimitry Andric case R_386_GOTOFF: 3000b57cec5SDimitry Andric case R_386_GOTPC: 3010b57cec5SDimitry Andric case R_386_PC32: 3020b57cec5SDimitry Andric case R_386_PLT32: 3030b57cec5SDimitry Andric case R_386_RELATIVE: 3040b57cec5SDimitry Andric case R_386_TLS_DTPMOD32: 3050b57cec5SDimitry Andric case R_386_TLS_DTPOFF32: 3060b57cec5SDimitry Andric case R_386_TLS_GD: 3070b57cec5SDimitry Andric case R_386_TLS_GOTIE: 3080b57cec5SDimitry Andric case R_386_TLS_IE: 3090b57cec5SDimitry Andric case R_386_TLS_LDM: 3100b57cec5SDimitry Andric case R_386_TLS_LDO_32: 3110b57cec5SDimitry Andric case R_386_TLS_LE: 3120b57cec5SDimitry Andric case R_386_TLS_LE_32: 3130b57cec5SDimitry Andric case R_386_TLS_TPOFF: 3140b57cec5SDimitry Andric case R_386_TLS_TPOFF32: 3150b57cec5SDimitry Andric checkInt(loc, val, 32, type); 3160b57cec5SDimitry Andric write32le(loc, val); 3170b57cec5SDimitry Andric break; 3180b57cec5SDimitry Andric default: 3190b57cec5SDimitry Andric llvm_unreachable("unknown relocation"); 3200b57cec5SDimitry Andric } 3210b57cec5SDimitry Andric } 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric void X86::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const { 3240b57cec5SDimitry Andric // Convert 3250b57cec5SDimitry Andric // leal x@tlsgd(, %ebx, 1), 3260b57cec5SDimitry Andric // call __tls_get_addr@plt 3270b57cec5SDimitry Andric // to 3280b57cec5SDimitry Andric // movl %gs:0,%eax 3290b57cec5SDimitry Andric // subl $x@ntpoff,%eax 3300b57cec5SDimitry Andric const uint8_t inst[] = { 3310b57cec5SDimitry Andric 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 3320b57cec5SDimitry Andric 0x81, 0xe8, 0, 0, 0, 0, // subl Val(%ebx), %eax 3330b57cec5SDimitry Andric }; 3340b57cec5SDimitry Andric memcpy(loc - 3, inst, sizeof(inst)); 3350b57cec5SDimitry Andric write32le(loc + 5, val); 3360b57cec5SDimitry Andric } 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric void X86::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const { 3390b57cec5SDimitry Andric // Convert 3400b57cec5SDimitry Andric // leal x@tlsgd(, %ebx, 1), 3410b57cec5SDimitry Andric // call __tls_get_addr@plt 3420b57cec5SDimitry Andric // to 3430b57cec5SDimitry Andric // movl %gs:0, %eax 3440b57cec5SDimitry Andric // addl x@gotntpoff(%ebx), %eax 3450b57cec5SDimitry Andric const uint8_t inst[] = { 3460b57cec5SDimitry Andric 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 3470b57cec5SDimitry Andric 0x03, 0x83, 0, 0, 0, 0, // addl Val(%ebx), %eax 3480b57cec5SDimitry Andric }; 3490b57cec5SDimitry Andric memcpy(loc - 3, inst, sizeof(inst)); 3500b57cec5SDimitry Andric write32le(loc + 5, val); 3510b57cec5SDimitry Andric } 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric // In some conditions, relocations can be optimized to avoid using GOT. 3540b57cec5SDimitry Andric // This function does that for Initial Exec to Local Exec case. 3550b57cec5SDimitry Andric void X86::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { 3560b57cec5SDimitry Andric // Ulrich's document section 6.2 says that @gotntpoff can 3570b57cec5SDimitry Andric // be used with MOVL or ADDL instructions. 3580b57cec5SDimitry Andric // @indntpoff is similar to @gotntpoff, but for use in 3590b57cec5SDimitry Andric // position dependent code. 3600b57cec5SDimitry Andric uint8_t reg = (loc[-1] >> 3) & 7; 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric if (type == R_386_TLS_IE) { 3630b57cec5SDimitry Andric if (loc[-1] == 0xa1) { 3640b57cec5SDimitry Andric // "movl foo@indntpoff,%eax" -> "movl $foo,%eax" 3650b57cec5SDimitry Andric // This case is different from the generic case below because 3660b57cec5SDimitry Andric // this is a 5 byte instruction while below is 6 bytes. 3670b57cec5SDimitry Andric loc[-1] = 0xb8; 3680b57cec5SDimitry Andric } else if (loc[-2] == 0x8b) { 3690b57cec5SDimitry Andric // "movl foo@indntpoff,%reg" -> "movl $foo,%reg" 3700b57cec5SDimitry Andric loc[-2] = 0xc7; 3710b57cec5SDimitry Andric loc[-1] = 0xc0 | reg; 3720b57cec5SDimitry Andric } else { 3730b57cec5SDimitry Andric // "addl foo@indntpoff,%reg" -> "addl $foo,%reg" 3740b57cec5SDimitry Andric loc[-2] = 0x81; 3750b57cec5SDimitry Andric loc[-1] = 0xc0 | reg; 3760b57cec5SDimitry Andric } 3770b57cec5SDimitry Andric } else { 3780b57cec5SDimitry Andric assert(type == R_386_TLS_GOTIE); 3790b57cec5SDimitry Andric if (loc[-2] == 0x8b) { 3800b57cec5SDimitry Andric // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg" 3810b57cec5SDimitry Andric loc[-2] = 0xc7; 3820b57cec5SDimitry Andric loc[-1] = 0xc0 | reg; 3830b57cec5SDimitry Andric } else { 3840b57cec5SDimitry Andric // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg" 3850b57cec5SDimitry Andric loc[-2] = 0x8d; 3860b57cec5SDimitry Andric loc[-1] = 0x80 | (reg << 3) | reg; 3870b57cec5SDimitry Andric } 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric write32le(loc, val); 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric void X86::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const { 3930b57cec5SDimitry Andric if (type == R_386_TLS_LDO_32) { 3940b57cec5SDimitry Andric write32le(loc, val); 3950b57cec5SDimitry Andric return; 3960b57cec5SDimitry Andric } 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric // Convert 3990b57cec5SDimitry Andric // leal foo(%reg),%eax 4000b57cec5SDimitry Andric // call ___tls_get_addr 4010b57cec5SDimitry Andric // to 4020b57cec5SDimitry Andric // movl %gs:0,%eax 4030b57cec5SDimitry Andric // nop 4040b57cec5SDimitry Andric // leal 0(%esi,1),%esi 4050b57cec5SDimitry Andric const uint8_t inst[] = { 4060b57cec5SDimitry Andric 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax 4070b57cec5SDimitry Andric 0x90, // nop 4080b57cec5SDimitry Andric 0x8d, 0x74, 0x26, 0x00, // leal 0(%esi,1),%esi 4090b57cec5SDimitry Andric }; 4100b57cec5SDimitry Andric memcpy(loc - 2, inst, sizeof(inst)); 4110b57cec5SDimitry Andric } 4120b57cec5SDimitry Andric 413*480093f4SDimitry Andric // If Intel Indirect Branch Tracking is enabled, we have to emit special PLT 414*480093f4SDimitry Andric // entries containing endbr32 instructions. A PLT entry will be split into two 415*480093f4SDimitry Andric // parts, one in .plt.sec (writePlt), and the other in .plt (writeIBTPlt). 416*480093f4SDimitry Andric namespace { 417*480093f4SDimitry Andric class IntelIBT : public X86 { 418*480093f4SDimitry Andric public: 419*480093f4SDimitry Andric IntelIBT(); 420*480093f4SDimitry Andric void writeGotPlt(uint8_t *buf, const Symbol &s) const override; 421*480093f4SDimitry Andric void writePlt(uint8_t *buf, const Symbol &sym, 422*480093f4SDimitry Andric uint64_t pltEntryAddr) const override; 423*480093f4SDimitry Andric void writeIBTPlt(uint8_t *buf, size_t numEntries) const override; 424*480093f4SDimitry Andric 425*480093f4SDimitry Andric static const unsigned IBTPltHeaderSize = 16; 426*480093f4SDimitry Andric }; 427*480093f4SDimitry Andric } // namespace 428*480093f4SDimitry Andric 429*480093f4SDimitry Andric IntelIBT::IntelIBT() { pltHeaderSize = 0; } 430*480093f4SDimitry Andric 431*480093f4SDimitry Andric void IntelIBT::writeGotPlt(uint8_t *buf, const Symbol &s) const { 432*480093f4SDimitry Andric uint64_t va = 433*480093f4SDimitry Andric in.ibtPlt->getVA() + IBTPltHeaderSize + s.pltIndex * pltEntrySize; 434*480093f4SDimitry Andric write32le(buf, va); 435*480093f4SDimitry Andric } 436*480093f4SDimitry Andric 437*480093f4SDimitry Andric void IntelIBT::writePlt(uint8_t *buf, const Symbol &sym, 438*480093f4SDimitry Andric uint64_t /*pltEntryAddr*/) const { 439*480093f4SDimitry Andric if (config->isPic) { 440*480093f4SDimitry Andric const uint8_t inst[] = { 441*480093f4SDimitry Andric 0xf3, 0x0f, 0x1e, 0xfb, // endbr32 442*480093f4SDimitry Andric 0xff, 0xa3, 0, 0, 0, 0, // jmp *name@GOT(%ebx) 443*480093f4SDimitry Andric 0x66, 0x0f, 0x1f, 0x44, 0, 0, // nop 444*480093f4SDimitry Andric }; 445*480093f4SDimitry Andric memcpy(buf, inst, sizeof(inst)); 446*480093f4SDimitry Andric write32le(buf + 6, sym.getGotPltVA() - in.gotPlt->getVA()); 447*480093f4SDimitry Andric return; 448*480093f4SDimitry Andric } 449*480093f4SDimitry Andric 450*480093f4SDimitry Andric const uint8_t inst[] = { 451*480093f4SDimitry Andric 0xf3, 0x0f, 0x1e, 0xfb, // endbr32 452*480093f4SDimitry Andric 0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT 453*480093f4SDimitry Andric 0x66, 0x0f, 0x1f, 0x44, 0, 0, // nop 454*480093f4SDimitry Andric }; 455*480093f4SDimitry Andric memcpy(buf, inst, sizeof(inst)); 456*480093f4SDimitry Andric write32le(buf + 6, sym.getGotPltVA()); 457*480093f4SDimitry Andric } 458*480093f4SDimitry Andric 459*480093f4SDimitry Andric void IntelIBT::writeIBTPlt(uint8_t *buf, size_t numEntries) const { 460*480093f4SDimitry Andric writePltHeader(buf); 461*480093f4SDimitry Andric buf += IBTPltHeaderSize; 462*480093f4SDimitry Andric 463*480093f4SDimitry Andric const uint8_t inst[] = { 464*480093f4SDimitry Andric 0xf3, 0x0f, 0x1e, 0xfb, // endbr32 465*480093f4SDimitry Andric 0x68, 0, 0, 0, 0, // pushl $reloc_offset 466*480093f4SDimitry Andric 0xe9, 0, 0, 0, 0, // jmpq .PLT0@PC 467*480093f4SDimitry Andric 0x66, 0x90, // nop 468*480093f4SDimitry Andric }; 469*480093f4SDimitry Andric 470*480093f4SDimitry Andric for (size_t i = 0; i < numEntries; ++i) { 471*480093f4SDimitry Andric memcpy(buf, inst, sizeof(inst)); 472*480093f4SDimitry Andric write32le(buf + 5, i * sizeof(object::ELF32LE::Rel)); 473*480093f4SDimitry Andric write32le(buf + 10, -pltHeaderSize - sizeof(inst) * i - 30); 474*480093f4SDimitry Andric buf += sizeof(inst); 475*480093f4SDimitry Andric } 476*480093f4SDimitry Andric } 477*480093f4SDimitry Andric 4780b57cec5SDimitry Andric namespace { 4790b57cec5SDimitry Andric class RetpolinePic : public X86 { 4800b57cec5SDimitry Andric public: 4810b57cec5SDimitry Andric RetpolinePic(); 4820b57cec5SDimitry Andric void writeGotPlt(uint8_t *buf, const Symbol &s) const override; 4830b57cec5SDimitry Andric void writePltHeader(uint8_t *buf) const override; 484*480093f4SDimitry Andric void writePlt(uint8_t *buf, const Symbol &sym, 485*480093f4SDimitry Andric uint64_t pltEntryAddr) const override; 4860b57cec5SDimitry Andric }; 4870b57cec5SDimitry Andric 4880b57cec5SDimitry Andric class RetpolineNoPic : public X86 { 4890b57cec5SDimitry Andric public: 4900b57cec5SDimitry Andric RetpolineNoPic(); 4910b57cec5SDimitry Andric void writeGotPlt(uint8_t *buf, const Symbol &s) const override; 4920b57cec5SDimitry Andric void writePltHeader(uint8_t *buf) const override; 493*480093f4SDimitry Andric void writePlt(uint8_t *buf, const Symbol &sym, 494*480093f4SDimitry Andric uint64_t pltEntryAddr) const override; 4950b57cec5SDimitry Andric }; 4960b57cec5SDimitry Andric } // namespace 4970b57cec5SDimitry Andric 4980b57cec5SDimitry Andric RetpolinePic::RetpolinePic() { 4990b57cec5SDimitry Andric pltHeaderSize = 48; 5000b57cec5SDimitry Andric pltEntrySize = 32; 501*480093f4SDimitry Andric ipltEntrySize = 32; 5020b57cec5SDimitry Andric } 5030b57cec5SDimitry Andric 5040b57cec5SDimitry Andric void RetpolinePic::writeGotPlt(uint8_t *buf, const Symbol &s) const { 5050b57cec5SDimitry Andric write32le(buf, s.getPltVA() + 17); 5060b57cec5SDimitry Andric } 5070b57cec5SDimitry Andric 5080b57cec5SDimitry Andric void RetpolinePic::writePltHeader(uint8_t *buf) const { 5090b57cec5SDimitry Andric const uint8_t insn[] = { 5100b57cec5SDimitry Andric 0xff, 0xb3, 4, 0, 0, 0, // 0: pushl 4(%ebx) 5110b57cec5SDimitry Andric 0x50, // 6: pushl %eax 5120b57cec5SDimitry Andric 0x8b, 0x83, 8, 0, 0, 0, // 7: mov 8(%ebx), %eax 5130b57cec5SDimitry Andric 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: call next 5140b57cec5SDimitry Andric 0xf3, 0x90, // 12: loop: pause 5150b57cec5SDimitry Andric 0x0f, 0xae, 0xe8, // 14: lfence 5160b57cec5SDimitry Andric 0xeb, 0xf9, // 17: jmp loop 5170b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 5180b57cec5SDimitry Andric 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) 5190b57cec5SDimitry Andric 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx 5200b57cec5SDimitry Andric 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) 5210b57cec5SDimitry Andric 0x89, 0xc8, // 2b: mov %ecx, %eax 5220b57cec5SDimitry Andric 0x59, // 2d: pop %ecx 5230b57cec5SDimitry Andric 0xc3, // 2e: ret 5240b57cec5SDimitry Andric 0xcc, // 2f: int3; padding 5250b57cec5SDimitry Andric }; 5260b57cec5SDimitry Andric memcpy(buf, insn, sizeof(insn)); 5270b57cec5SDimitry Andric } 5280b57cec5SDimitry Andric 529*480093f4SDimitry Andric void RetpolinePic::writePlt(uint8_t *buf, const Symbol &sym, 530*480093f4SDimitry Andric uint64_t pltEntryAddr) const { 531*480093f4SDimitry Andric unsigned relOff = in.relaPlt->entsize * sym.pltIndex; 5320b57cec5SDimitry Andric const uint8_t insn[] = { 5330b57cec5SDimitry Andric 0x50, // pushl %eax 5340b57cec5SDimitry Andric 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax 5350b57cec5SDimitry Andric 0xe8, 0, 0, 0, 0, // call plt+0x20 5360b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // jmp plt+0x12 5370b57cec5SDimitry Andric 0x68, 0, 0, 0, 0, // pushl $reloc_offset 5380b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // jmp plt+0 5390b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding 5400b57cec5SDimitry Andric }; 5410b57cec5SDimitry Andric memcpy(buf, insn, sizeof(insn)); 5420b57cec5SDimitry Andric 5430b57cec5SDimitry Andric uint32_t ebx = in.gotPlt->getVA(); 544*480093f4SDimitry Andric unsigned off = pltEntryAddr - in.plt->getVA(); 545*480093f4SDimitry Andric write32le(buf + 3, sym.getGotPltVA() - ebx); 5460b57cec5SDimitry Andric write32le(buf + 8, -off - 12 + 32); 5470b57cec5SDimitry Andric write32le(buf + 13, -off - 17 + 18); 5480b57cec5SDimitry Andric write32le(buf + 18, relOff); 5490b57cec5SDimitry Andric write32le(buf + 23, -off - 27); 5500b57cec5SDimitry Andric } 5510b57cec5SDimitry Andric 5520b57cec5SDimitry Andric RetpolineNoPic::RetpolineNoPic() { 5530b57cec5SDimitry Andric pltHeaderSize = 48; 5540b57cec5SDimitry Andric pltEntrySize = 32; 555*480093f4SDimitry Andric ipltEntrySize = 32; 5560b57cec5SDimitry Andric } 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric void RetpolineNoPic::writeGotPlt(uint8_t *buf, const Symbol &s) const { 5590b57cec5SDimitry Andric write32le(buf, s.getPltVA() + 16); 5600b57cec5SDimitry Andric } 5610b57cec5SDimitry Andric 5620b57cec5SDimitry Andric void RetpolineNoPic::writePltHeader(uint8_t *buf) const { 5630b57cec5SDimitry Andric const uint8_t insn[] = { 5640b57cec5SDimitry Andric 0xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+4 5650b57cec5SDimitry Andric 0x50, // 6: pushl %eax 5660b57cec5SDimitry Andric 0xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax 5670b57cec5SDimitry Andric 0xe8, 0x0f, 0x00, 0x00, 0x00, // c: call next 5680b57cec5SDimitry Andric 0xf3, 0x90, // 11: loop: pause 5690b57cec5SDimitry Andric 0x0f, 0xae, 0xe8, // 13: lfence 5700b57cec5SDimitry Andric 0xeb, 0xf9, // 16: jmp loop 5710b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 18: int3 5720b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, // 1f: int3; .align 16 5730b57cec5SDimitry Andric 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) 5740b57cec5SDimitry Andric 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx 5750b57cec5SDimitry Andric 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) 5760b57cec5SDimitry Andric 0x89, 0xc8, // 2b: mov %ecx, %eax 5770b57cec5SDimitry Andric 0x59, // 2d: pop %ecx 5780b57cec5SDimitry Andric 0xc3, // 2e: ret 5790b57cec5SDimitry Andric 0xcc, // 2f: int3; padding 5800b57cec5SDimitry Andric }; 5810b57cec5SDimitry Andric memcpy(buf, insn, sizeof(insn)); 5820b57cec5SDimitry Andric 5830b57cec5SDimitry Andric uint32_t gotPlt = in.gotPlt->getVA(); 5840b57cec5SDimitry Andric write32le(buf + 2, gotPlt + 4); 5850b57cec5SDimitry Andric write32le(buf + 8, gotPlt + 8); 5860b57cec5SDimitry Andric } 5870b57cec5SDimitry Andric 588*480093f4SDimitry Andric void RetpolineNoPic::writePlt(uint8_t *buf, const Symbol &sym, 589*480093f4SDimitry Andric uint64_t pltEntryAddr) const { 590*480093f4SDimitry Andric unsigned relOff = in.relaPlt->entsize * sym.pltIndex; 5910b57cec5SDimitry Andric const uint8_t insn[] = { 5920b57cec5SDimitry Andric 0x50, // 0: pushl %eax 5930b57cec5SDimitry Andric 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax 5940b57cec5SDimitry Andric 0xe8, 0, 0, 0, 0, // 6: call plt+0x20 5950b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11 5960b57cec5SDimitry Andric 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset 5970b57cec5SDimitry Andric 0xe9, 0, 0, 0, 0, // 15: jmp plt+0 5980b57cec5SDimitry Andric 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding 5990b57cec5SDimitry Andric 0xcc, // 1f: int3; padding 6000b57cec5SDimitry Andric }; 6010b57cec5SDimitry Andric memcpy(buf, insn, sizeof(insn)); 6020b57cec5SDimitry Andric 603*480093f4SDimitry Andric unsigned off = pltEntryAddr - in.plt->getVA(); 604*480093f4SDimitry Andric write32le(buf + 2, sym.getGotPltVA()); 6050b57cec5SDimitry Andric write32le(buf + 7, -off - 11 + 32); 6060b57cec5SDimitry Andric write32le(buf + 12, -off - 16 + 17); 6070b57cec5SDimitry Andric write32le(buf + 17, relOff); 6080b57cec5SDimitry Andric write32le(buf + 22, -off - 26); 6090b57cec5SDimitry Andric } 6100b57cec5SDimitry Andric 61185868e8aSDimitry Andric TargetInfo *getX86TargetInfo() { 6120b57cec5SDimitry Andric if (config->zRetpolineplt) { 6130b57cec5SDimitry Andric if (config->isPic) { 6140b57cec5SDimitry Andric static RetpolinePic t; 6150b57cec5SDimitry Andric return &t; 6160b57cec5SDimitry Andric } 6170b57cec5SDimitry Andric static RetpolineNoPic t; 6180b57cec5SDimitry Andric return &t; 6190b57cec5SDimitry Andric } 6200b57cec5SDimitry Andric 621*480093f4SDimitry Andric if (config->andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT) { 622*480093f4SDimitry Andric static IntelIBT t; 623*480093f4SDimitry Andric return &t; 624*480093f4SDimitry Andric } 625*480093f4SDimitry Andric 6260b57cec5SDimitry Andric static X86 t; 6270b57cec5SDimitry Andric return &t; 6280b57cec5SDimitry Andric } 62985868e8aSDimitry Andric 63085868e8aSDimitry Andric } // namespace elf 63185868e8aSDimitry Andric } // namespace lld 632