xref: /openbsd-src/gnu/llvm/lld/ELF/Arch/X86.cpp (revision dfe94b169149f14cc1aee2cf6dad58a8d9a1860c)
1ece8a530Spatrick //===- X86.cpp ------------------------------------------------------------===//
2ece8a530Spatrick //
3ece8a530Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ece8a530Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ece8a530Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ece8a530Spatrick //
7ece8a530Spatrick //===----------------------------------------------------------------------===//
8ece8a530Spatrick 
9*dfe94b16Srobert #include "OutputSections.h"
10ece8a530Spatrick #include "Symbols.h"
11ece8a530Spatrick #include "SyntheticSections.h"
12ece8a530Spatrick #include "Target.h"
13ece8a530Spatrick #include "lld/Common/ErrorHandler.h"
14ece8a530Spatrick #include "llvm/Support/Endian.h"
15ece8a530Spatrick 
16ece8a530Spatrick using namespace llvm;
17ece8a530Spatrick using namespace llvm::support::endian;
18ece8a530Spatrick using namespace llvm::ELF;
19bb684c34Spatrick using namespace lld;
20bb684c34Spatrick using namespace lld::elf;
21ece8a530Spatrick 
22ece8a530Spatrick namespace {
23ece8a530Spatrick class X86 : public TargetInfo {
24ece8a530Spatrick public:
25ece8a530Spatrick   X86();
26ece8a530Spatrick   int getTlsGdRelaxSkip(RelType type) const override;
27ece8a530Spatrick   RelExpr getRelExpr(RelType type, const Symbol &s,
28ece8a530Spatrick                      const uint8_t *loc) const override;
29ece8a530Spatrick   int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
30ece8a530Spatrick   void writeGotPltHeader(uint8_t *buf) const override;
31ece8a530Spatrick   RelType getDynRel(RelType type) const override;
32ece8a530Spatrick   void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
33ece8a530Spatrick   void writeIgotPlt(uint8_t *buf, const Symbol &s) const override;
34ece8a530Spatrick   void writePltHeader(uint8_t *buf) const override;
35ece8a530Spatrick   void writePlt(uint8_t *buf, const Symbol &sym,
36ece8a530Spatrick                 uint64_t pltEntryAddr) const override;
37bb684c34Spatrick   void relocate(uint8_t *loc, const Relocation &rel,
38bb684c34Spatrick                 uint64_t val) const override;
39ece8a530Spatrick 
401cf9926bSpatrick   RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;
41*dfe94b16Srobert   void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
42ece8a530Spatrick };
43ece8a530Spatrick } // namespace
44ece8a530Spatrick 
X86()45ece8a530Spatrick X86::X86() {
46ece8a530Spatrick   copyRel = R_386_COPY;
47ece8a530Spatrick   gotRel = R_386_GLOB_DAT;
48ece8a530Spatrick   pltRel = R_386_JUMP_SLOT;
49ece8a530Spatrick   iRelativeRel = R_386_IRELATIVE;
50ece8a530Spatrick   relativeRel = R_386_RELATIVE;
51ece8a530Spatrick   symbolicRel = R_386_32;
52*dfe94b16Srobert   tlsDescRel = R_386_TLS_DESC;
53ece8a530Spatrick   tlsGotRel = R_386_TLS_TPOFF;
54ece8a530Spatrick   tlsModuleIndexRel = R_386_TLS_DTPMOD32;
55ece8a530Spatrick   tlsOffsetRel = R_386_TLS_DTPOFF32;
56*dfe94b16Srobert   gotBaseSymInGotPlt = true;
57ece8a530Spatrick   pltHeaderSize = 16;
58ece8a530Spatrick   pltEntrySize = 16;
59ece8a530Spatrick   ipltEntrySize = 16;
60ece8a530Spatrick   trapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3
61ece8a530Spatrick 
62ece8a530Spatrick   // Align to the non-PAE large page size (known as a superpage or huge page).
63ece8a530Spatrick   // FreeBSD automatically promotes large, superpage-aligned allocations.
64ece8a530Spatrick   defaultImageBase = 0x400000;
65ece8a530Spatrick }
66ece8a530Spatrick 
getTlsGdRelaxSkip(RelType type) const67ece8a530Spatrick int X86::getTlsGdRelaxSkip(RelType type) const {
68*dfe94b16Srobert   // TLSDESC relocations are processed separately. See relaxTlsGdToLe below.
69*dfe94b16Srobert   return type == R_386_TLS_GOTDESC || type == R_386_TLS_DESC_CALL ? 1 : 2;
70ece8a530Spatrick }
71ece8a530Spatrick 
getRelExpr(RelType type,const Symbol & s,const uint8_t * loc) const72ece8a530Spatrick RelExpr X86::getRelExpr(RelType type, const Symbol &s,
73ece8a530Spatrick                         const uint8_t *loc) const {
74ece8a530Spatrick   switch (type) {
75ece8a530Spatrick   case R_386_8:
76ece8a530Spatrick   case R_386_16:
77ece8a530Spatrick   case R_386_32:
78ece8a530Spatrick     return R_ABS;
79ece8a530Spatrick   case R_386_TLS_LDO_32:
80ece8a530Spatrick     return R_DTPREL;
81ece8a530Spatrick   case R_386_TLS_GD:
82ece8a530Spatrick     return R_TLSGD_GOTPLT;
83ece8a530Spatrick   case R_386_TLS_LDM:
84ece8a530Spatrick     return R_TLSLD_GOTPLT;
85ece8a530Spatrick   case R_386_PLT32:
86ece8a530Spatrick     return R_PLT_PC;
87ece8a530Spatrick   case R_386_PC8:
88ece8a530Spatrick   case R_386_PC16:
89ece8a530Spatrick   case R_386_PC32:
90ece8a530Spatrick     return R_PC;
91ece8a530Spatrick   case R_386_GOTPC:
92ece8a530Spatrick     return R_GOTPLTONLY_PC;
93ece8a530Spatrick   case R_386_TLS_IE:
94ece8a530Spatrick     return R_GOT;
95ece8a530Spatrick   case R_386_GOT32:
96ece8a530Spatrick   case R_386_GOT32X:
97ece8a530Spatrick     // These relocations are arguably mis-designed because their calculations
98ece8a530Spatrick     // depend on the instructions they are applied to. This is bad because we
99ece8a530Spatrick     // usually don't care about whether the target section contains valid
100ece8a530Spatrick     // machine instructions or not. But this is part of the documented ABI, so
101ece8a530Spatrick     // we had to implement as the standard requires.
102ece8a530Spatrick     //
103ece8a530Spatrick     // x86 does not support PC-relative data access. Therefore, in order to
104ece8a530Spatrick     // access GOT contents, a GOT address needs to be known at link-time
105ece8a530Spatrick     // (which means non-PIC) or compilers have to emit code to get a GOT
106ece8a530Spatrick     // address at runtime (which means code is position-independent but
107ece8a530Spatrick     // compilers need to emit extra code for each GOT access.) This decision
108ece8a530Spatrick     // is made at compile-time. In the latter case, compilers emit code to
109ece8a530Spatrick     // load a GOT address to a register, which is usually %ebx.
110ece8a530Spatrick     //
111ece8a530Spatrick     // So, there are two ways to refer to symbol foo's GOT entry: foo@GOT or
112ece8a530Spatrick     // foo@GOT(%ebx).
113ece8a530Spatrick     //
114ece8a530Spatrick     // foo@GOT is not usable in PIC. If we are creating a PIC output and if we
115ece8a530Spatrick     // find such relocation, we should report an error. foo@GOT is resolved to
116ece8a530Spatrick     // an *absolute* address of foo's GOT entry, because both GOT address and
117ece8a530Spatrick     // foo's offset are known. In other words, it's G + A.
118ece8a530Spatrick     //
119ece8a530Spatrick     // foo@GOT(%ebx) needs to be resolved to a *relative* offset from a GOT to
120ece8a530Spatrick     // foo's GOT entry in the table, because GOT address is not known but foo's
121ece8a530Spatrick     // offset in the table is known. It's G + A - GOT.
122ece8a530Spatrick     //
123ece8a530Spatrick     // It's unfortunate that compilers emit the same relocation for these
124ece8a530Spatrick     // different use cases. In order to distinguish them, we have to read a
125ece8a530Spatrick     // machine instruction.
126ece8a530Spatrick     //
127ece8a530Spatrick     // The following code implements it. We assume that Loc[0] is the first byte
128ece8a530Spatrick     // of a displacement or an immediate field of a valid machine
129ece8a530Spatrick     // instruction. That means a ModRM byte is at Loc[-1]. By taking a look at
130ece8a530Spatrick     // the byte, we can determine whether the instruction uses the operand as an
131ece8a530Spatrick     // absolute address (R_GOT) or a register-relative address (R_GOTPLT).
132ece8a530Spatrick     return (loc[-1] & 0xc7) == 0x5 ? R_GOT : R_GOTPLT;
133*dfe94b16Srobert   case R_386_TLS_GOTDESC:
134*dfe94b16Srobert     return R_TLSDESC_GOTPLT;
135*dfe94b16Srobert   case R_386_TLS_DESC_CALL:
136*dfe94b16Srobert     return R_TLSDESC_CALL;
137ece8a530Spatrick   case R_386_TLS_GOTIE:
138ece8a530Spatrick     return R_GOTPLT;
139ece8a530Spatrick   case R_386_GOTOFF:
140ece8a530Spatrick     return R_GOTPLTREL;
141ece8a530Spatrick   case R_386_TLS_LE:
1421cf9926bSpatrick     return R_TPREL;
143ece8a530Spatrick   case R_386_TLS_LE_32:
1441cf9926bSpatrick     return R_TPREL_NEG;
145ece8a530Spatrick   case R_386_NONE:
146ece8a530Spatrick     return R_NONE;
147ece8a530Spatrick   default:
148ece8a530Spatrick     error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
149ece8a530Spatrick           ") against symbol " + toString(s));
150ece8a530Spatrick     return R_NONE;
151ece8a530Spatrick   }
152ece8a530Spatrick }
153ece8a530Spatrick 
adjustTlsExpr(RelType type,RelExpr expr) const1541cf9926bSpatrick RelExpr X86::adjustTlsExpr(RelType type, RelExpr expr) const {
155ece8a530Spatrick   switch (expr) {
156ece8a530Spatrick   default:
157ece8a530Spatrick     return expr;
158ece8a530Spatrick   case R_RELAX_TLS_GD_TO_IE:
159ece8a530Spatrick     return R_RELAX_TLS_GD_TO_IE_GOTPLT;
160ece8a530Spatrick   case R_RELAX_TLS_GD_TO_LE:
161*dfe94b16Srobert     return type == R_386_TLS_GD ? R_RELAX_TLS_GD_TO_LE_NEG
162*dfe94b16Srobert                                 : R_RELAX_TLS_GD_TO_LE;
163ece8a530Spatrick   }
164ece8a530Spatrick }
165ece8a530Spatrick 
writeGotPltHeader(uint8_t * buf) const166ece8a530Spatrick void X86::writeGotPltHeader(uint8_t *buf) const {
167ece8a530Spatrick   write32le(buf, mainPart->dynamic->getVA());
168ece8a530Spatrick }
169ece8a530Spatrick 
writeGotPlt(uint8_t * buf,const Symbol & s) const170ece8a530Spatrick void X86::writeGotPlt(uint8_t *buf, const Symbol &s) const {
171ece8a530Spatrick   // Entries in .got.plt initially points back to the corresponding
172ece8a530Spatrick   // PLT entries with a fixed offset to skip the first instruction.
173ece8a530Spatrick   write32le(buf, s.getPltVA() + 6);
174ece8a530Spatrick }
175ece8a530Spatrick 
writeIgotPlt(uint8_t * buf,const Symbol & s) const176ece8a530Spatrick void X86::writeIgotPlt(uint8_t *buf, const Symbol &s) const {
177ece8a530Spatrick   // An x86 entry is the address of the ifunc resolver function.
178ece8a530Spatrick   write32le(buf, s.getVA());
179ece8a530Spatrick }
180ece8a530Spatrick 
getDynRel(RelType type) const181ece8a530Spatrick RelType X86::getDynRel(RelType type) const {
182ece8a530Spatrick   if (type == R_386_TLS_LE)
183ece8a530Spatrick     return R_386_TLS_TPOFF;
184ece8a530Spatrick   if (type == R_386_TLS_LE_32)
185ece8a530Spatrick     return R_386_TLS_TPOFF32;
186ece8a530Spatrick   return type;
187ece8a530Spatrick }
188ece8a530Spatrick 
writePltHeader(uint8_t * buf) const189ece8a530Spatrick void X86::writePltHeader(uint8_t *buf) const {
190ece8a530Spatrick   if (config->isPic) {
191ece8a530Spatrick     const uint8_t v[] = {
192ece8a530Spatrick         0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx)
193ece8a530Spatrick         0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx)
194ece8a530Spatrick         0x90, 0x90, 0x90, 0x90              // nop
195ece8a530Spatrick     };
196ece8a530Spatrick     memcpy(buf, v, sizeof(v));
197ece8a530Spatrick     return;
198ece8a530Spatrick   }
199ece8a530Spatrick 
200ece8a530Spatrick   const uint8_t pltData[] = {
201ece8a530Spatrick       0xff, 0x35, 0, 0, 0, 0, // pushl (GOTPLT+4)
202ece8a530Spatrick       0xff, 0x25, 0, 0, 0, 0, // jmp *(GOTPLT+8)
203ece8a530Spatrick       0x90, 0x90, 0x90, 0x90, // nop
204ece8a530Spatrick   };
205ece8a530Spatrick   memcpy(buf, pltData, sizeof(pltData));
206ece8a530Spatrick   uint32_t gotPlt = in.gotPlt->getVA();
207ece8a530Spatrick   write32le(buf + 2, gotPlt + 4);
208ece8a530Spatrick   write32le(buf + 8, gotPlt + 8);
209ece8a530Spatrick }
210ece8a530Spatrick 
writePlt(uint8_t * buf,const Symbol & sym,uint64_t pltEntryAddr) const211ece8a530Spatrick void X86::writePlt(uint8_t *buf, const Symbol &sym,
212ece8a530Spatrick                    uint64_t pltEntryAddr) const {
213*dfe94b16Srobert   unsigned relOff = in.relaPlt->entsize * sym.getPltIdx();
214ece8a530Spatrick   if (config->isPic) {
215ece8a530Spatrick     const uint8_t inst[] = {
216ece8a530Spatrick         0xff, 0xa3, 0, 0, 0, 0, // jmp *foo@GOT(%ebx)
217ece8a530Spatrick         0x68, 0,    0, 0, 0,    // pushl $reloc_offset
218ece8a530Spatrick         0xe9, 0,    0, 0, 0,    // jmp .PLT0@PC
219ece8a530Spatrick     };
220ece8a530Spatrick     memcpy(buf, inst, sizeof(inst));
221ece8a530Spatrick     write32le(buf + 2, sym.getGotPltVA() - in.gotPlt->getVA());
222ece8a530Spatrick   } else {
223ece8a530Spatrick     const uint8_t inst[] = {
224ece8a530Spatrick         0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT
225ece8a530Spatrick         0x68, 0,    0, 0, 0,    // pushl $reloc_offset
226ece8a530Spatrick         0xe9, 0,    0, 0, 0,    // jmp .PLT0@PC
227ece8a530Spatrick     };
228ece8a530Spatrick     memcpy(buf, inst, sizeof(inst));
229ece8a530Spatrick     write32le(buf + 2, sym.getGotPltVA());
230ece8a530Spatrick   }
231ece8a530Spatrick 
232ece8a530Spatrick   write32le(buf + 7, relOff);
233ece8a530Spatrick   write32le(buf + 12, in.plt->getVA() - pltEntryAddr - 16);
234ece8a530Spatrick }
235ece8a530Spatrick 
getImplicitAddend(const uint8_t * buf,RelType type) const236ece8a530Spatrick int64_t X86::getImplicitAddend(const uint8_t *buf, RelType type) const {
237ece8a530Spatrick   switch (type) {
238ece8a530Spatrick   case R_386_8:
239ece8a530Spatrick   case R_386_PC8:
240ece8a530Spatrick     return SignExtend64<8>(*buf);
241ece8a530Spatrick   case R_386_16:
242ece8a530Spatrick   case R_386_PC16:
243ece8a530Spatrick     return SignExtend64<16>(read16le(buf));
244ece8a530Spatrick   case R_386_32:
2451cf9926bSpatrick   case R_386_GLOB_DAT:
246ece8a530Spatrick   case R_386_GOT32:
247ece8a530Spatrick   case R_386_GOT32X:
248ece8a530Spatrick   case R_386_GOTOFF:
249ece8a530Spatrick   case R_386_GOTPC:
2501cf9926bSpatrick   case R_386_IRELATIVE:
251ece8a530Spatrick   case R_386_PC32:
252ece8a530Spatrick   case R_386_PLT32:
2531cf9926bSpatrick   case R_386_RELATIVE:
254*dfe94b16Srobert   case R_386_TLS_GOTDESC:
255*dfe94b16Srobert   case R_386_TLS_DESC_CALL:
2561cf9926bSpatrick   case R_386_TLS_DTPMOD32:
2571cf9926bSpatrick   case R_386_TLS_DTPOFF32:
258ece8a530Spatrick   case R_386_TLS_LDO_32:
2591cf9926bSpatrick   case R_386_TLS_LDM:
2601cf9926bSpatrick   case R_386_TLS_IE:
2611cf9926bSpatrick   case R_386_TLS_IE_32:
262ece8a530Spatrick   case R_386_TLS_LE:
2631cf9926bSpatrick   case R_386_TLS_LE_32:
2641cf9926bSpatrick   case R_386_TLS_GD:
2651cf9926bSpatrick   case R_386_TLS_GD_32:
2661cf9926bSpatrick   case R_386_TLS_GOTIE:
2671cf9926bSpatrick   case R_386_TLS_TPOFF:
2681cf9926bSpatrick   case R_386_TLS_TPOFF32:
269ece8a530Spatrick     return SignExtend64<32>(read32le(buf));
270*dfe94b16Srobert   case R_386_TLS_DESC:
271*dfe94b16Srobert     return SignExtend64<32>(read32le(buf + 4));
2721cf9926bSpatrick   case R_386_NONE:
2731cf9926bSpatrick   case R_386_JUMP_SLOT:
2741cf9926bSpatrick     // These relocations are defined as not having an implicit addend.
2751cf9926bSpatrick     return 0;
276ece8a530Spatrick   default:
2771cf9926bSpatrick     internalLinkerError(getErrorLocation(buf),
2781cf9926bSpatrick                         "cannot read addend for relocation " + toString(type));
279ece8a530Spatrick     return 0;
280ece8a530Spatrick   }
281ece8a530Spatrick }
282ece8a530Spatrick 
relocate(uint8_t * loc,const Relocation & rel,uint64_t val) const283bb684c34Spatrick void X86::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
284bb684c34Spatrick   switch (rel.type) {
285ece8a530Spatrick   case R_386_8:
286ece8a530Spatrick     // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are
287ece8a530Spatrick     // being used for some 16-bit programs such as boot loaders, so
288ece8a530Spatrick     // we want to support them.
289bb684c34Spatrick     checkIntUInt(loc, val, 8, rel);
290ece8a530Spatrick     *loc = val;
291ece8a530Spatrick     break;
292ece8a530Spatrick   case R_386_PC8:
293bb684c34Spatrick     checkInt(loc, val, 8, rel);
294ece8a530Spatrick     *loc = val;
295ece8a530Spatrick     break;
296ece8a530Spatrick   case R_386_16:
297bb684c34Spatrick     checkIntUInt(loc, val, 16, rel);
298ece8a530Spatrick     write16le(loc, val);
299ece8a530Spatrick     break;
300ece8a530Spatrick   case R_386_PC16:
301ece8a530Spatrick     // R_386_PC16 is normally used with 16 bit code. In that situation
302ece8a530Spatrick     // the PC is 16 bits, just like the addend. This means that it can
303ece8a530Spatrick     // point from any 16 bit address to any other if the possibility
304ece8a530Spatrick     // of wrapping is included.
305ece8a530Spatrick     // The only restriction we have to check then is that the destination
306ece8a530Spatrick     // address fits in 16 bits. That is impossible to do here. The problem is
307ece8a530Spatrick     // that we are passed the final value, which already had the
308ece8a530Spatrick     // current location subtracted from it.
309ece8a530Spatrick     // We just check that Val fits in 17 bits. This misses some cases, but
310ece8a530Spatrick     // should have no false positives.
311bb684c34Spatrick     checkInt(loc, val, 17, rel);
312ece8a530Spatrick     write16le(loc, val);
313ece8a530Spatrick     break;
314ece8a530Spatrick   case R_386_32:
315ece8a530Spatrick   case R_386_GOT32:
316ece8a530Spatrick   case R_386_GOT32X:
317ece8a530Spatrick   case R_386_GOTOFF:
318ece8a530Spatrick   case R_386_GOTPC:
319ece8a530Spatrick   case R_386_PC32:
320ece8a530Spatrick   case R_386_PLT32:
321ece8a530Spatrick   case R_386_RELATIVE:
322*dfe94b16Srobert   case R_386_TLS_GOTDESC:
323*dfe94b16Srobert   case R_386_TLS_DESC_CALL:
324ece8a530Spatrick   case R_386_TLS_DTPMOD32:
325ece8a530Spatrick   case R_386_TLS_DTPOFF32:
326ece8a530Spatrick   case R_386_TLS_GD:
327ece8a530Spatrick   case R_386_TLS_GOTIE:
328ece8a530Spatrick   case R_386_TLS_IE:
329ece8a530Spatrick   case R_386_TLS_LDM:
330ece8a530Spatrick   case R_386_TLS_LDO_32:
331ece8a530Spatrick   case R_386_TLS_LE:
332ece8a530Spatrick   case R_386_TLS_LE_32:
333ece8a530Spatrick   case R_386_TLS_TPOFF:
334ece8a530Spatrick   case R_386_TLS_TPOFF32:
335bb684c34Spatrick     checkInt(loc, val, 32, rel);
336ece8a530Spatrick     write32le(loc, val);
337ece8a530Spatrick     break;
338*dfe94b16Srobert   case R_386_TLS_DESC:
339*dfe94b16Srobert     // The addend is stored in the second 32-bit word.
340*dfe94b16Srobert     write32le(loc + 4, val);
341*dfe94b16Srobert     break;
342ece8a530Spatrick   default:
343ece8a530Spatrick     llvm_unreachable("unknown relocation");
344ece8a530Spatrick   }
345ece8a530Spatrick }
346ece8a530Spatrick 
relaxTlsGdToLe(uint8_t * loc,const Relocation & rel,uint64_t val)347*dfe94b16Srobert static void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) {
348*dfe94b16Srobert   if (rel.type == R_386_TLS_GD) {
349*dfe94b16Srobert     // Convert (loc[-2] == 0x04)
350*dfe94b16Srobert     //   leal x@tlsgd(, %ebx, 1), %eax
351*dfe94b16Srobert     //   call ___tls_get_addr@plt
352*dfe94b16Srobert     // or
353*dfe94b16Srobert     //   leal x@tlsgd(%reg), %eax
354*dfe94b16Srobert     //   call *___tls_get_addr@got(%reg)
355ece8a530Spatrick     // to
356ece8a530Spatrick     const uint8_t inst[] = {
357ece8a530Spatrick         0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
358*dfe94b16Srobert         0x81, 0xe8, 0,    0,    0,    0,    // subl x@ntpoff(%ebx), %eax
359ece8a530Spatrick     };
360*dfe94b16Srobert     uint8_t *w = loc[-2] == 0x04 ? loc - 3 : loc - 2;
361*dfe94b16Srobert     memcpy(w, inst, sizeof(inst));
362*dfe94b16Srobert     write32le(w + 8, val);
363*dfe94b16Srobert   } else if (rel.type == R_386_TLS_GOTDESC) {
364*dfe94b16Srobert     // Convert leal x@tlsdesc(%ebx), %eax to leal x@ntpoff, %eax.
365*dfe94b16Srobert     //
366*dfe94b16Srobert     // Note: call *x@tlsdesc(%eax) may not immediately follow this instruction.
367*dfe94b16Srobert     if (memcmp(loc - 2, "\x8d\x83", 2)) {
368*dfe94b16Srobert       error(getErrorLocation(loc - 2) +
369*dfe94b16Srobert             "R_386_TLS_GOTDESC must be used in leal x@tlsdesc(%ebx), %eax");
370*dfe94b16Srobert       return;
371*dfe94b16Srobert     }
372*dfe94b16Srobert     loc[-1] = 0x05;
373*dfe94b16Srobert     write32le(loc, val);
374*dfe94b16Srobert   } else {
375*dfe94b16Srobert     // Convert call *x@tlsdesc(%eax) to xchg ax, ax.
376*dfe94b16Srobert     assert(rel.type == R_386_TLS_DESC_CALL);
377*dfe94b16Srobert     loc[0] = 0x66;
378*dfe94b16Srobert     loc[1] = 0x90;
379*dfe94b16Srobert   }
380ece8a530Spatrick }
381ece8a530Spatrick 
relaxTlsGdToIe(uint8_t * loc,const Relocation & rel,uint64_t val)382*dfe94b16Srobert static void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) {
383*dfe94b16Srobert   if (rel.type == R_386_TLS_GD) {
384*dfe94b16Srobert     // Convert (loc[-2] == 0x04)
385*dfe94b16Srobert     //   leal x@tlsgd(, %ebx, 1), %eax
386*dfe94b16Srobert     //   call ___tls_get_addr@plt
387*dfe94b16Srobert     // or
388*dfe94b16Srobert     //   leal x@tlsgd(%reg), %eax
389*dfe94b16Srobert     //   call *___tls_get_addr@got(%reg)
390ece8a530Spatrick     const uint8_t inst[] = {
391ece8a530Spatrick         0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
392*dfe94b16Srobert         0x03, 0x83, 0,    0,    0,    0,    // addl x@gottpoff(%ebx), %eax
393ece8a530Spatrick     };
394*dfe94b16Srobert     uint8_t *w = loc[-2] == 0x04 ? loc - 3 : loc - 2;
395*dfe94b16Srobert     memcpy(w, inst, sizeof(inst));
396*dfe94b16Srobert     write32le(w + 8, val);
397*dfe94b16Srobert   } else if (rel.type == R_386_TLS_GOTDESC) {
398*dfe94b16Srobert     // Convert leal x@tlsdesc(%ebx), %eax to movl x@gotntpoff(%ebx), %eax.
399*dfe94b16Srobert     if (memcmp(loc - 2, "\x8d\x83", 2)) {
400*dfe94b16Srobert       error(getErrorLocation(loc - 2) +
401*dfe94b16Srobert             "R_386_TLS_GOTDESC must be used in leal x@tlsdesc(%ebx), %eax");
402*dfe94b16Srobert       return;
403*dfe94b16Srobert     }
404*dfe94b16Srobert     loc[-2] = 0x8b;
405*dfe94b16Srobert     write32le(loc, val);
406*dfe94b16Srobert   } else {
407*dfe94b16Srobert     // Convert call *x@tlsdesc(%eax) to xchg ax, ax.
408*dfe94b16Srobert     assert(rel.type == R_386_TLS_DESC_CALL);
409*dfe94b16Srobert     loc[0] = 0x66;
410*dfe94b16Srobert     loc[1] = 0x90;
411*dfe94b16Srobert   }
412ece8a530Spatrick }
413ece8a530Spatrick 
414ece8a530Spatrick // In some conditions, relocations can be optimized to avoid using GOT.
415ece8a530Spatrick // This function does that for Initial Exec to Local Exec case.
relaxTlsIeToLe(uint8_t * loc,const Relocation & rel,uint64_t val)416*dfe94b16Srobert static void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) {
417ece8a530Spatrick   // Ulrich's document section 6.2 says that @gotntpoff can
418ece8a530Spatrick   // be used with MOVL or ADDL instructions.
419ece8a530Spatrick   // @indntpoff is similar to @gotntpoff, but for use in
420ece8a530Spatrick   // position dependent code.
421ece8a530Spatrick   uint8_t reg = (loc[-1] >> 3) & 7;
422ece8a530Spatrick 
423bb684c34Spatrick   if (rel.type == R_386_TLS_IE) {
424ece8a530Spatrick     if (loc[-1] == 0xa1) {
425ece8a530Spatrick       // "movl foo@indntpoff,%eax" -> "movl $foo,%eax"
426ece8a530Spatrick       // This case is different from the generic case below because
427ece8a530Spatrick       // this is a 5 byte instruction while below is 6 bytes.
428ece8a530Spatrick       loc[-1] = 0xb8;
429ece8a530Spatrick     } else if (loc[-2] == 0x8b) {
430ece8a530Spatrick       // "movl foo@indntpoff,%reg" -> "movl $foo,%reg"
431ece8a530Spatrick       loc[-2] = 0xc7;
432ece8a530Spatrick       loc[-1] = 0xc0 | reg;
433ece8a530Spatrick     } else {
434ece8a530Spatrick       // "addl foo@indntpoff,%reg" -> "addl $foo,%reg"
435ece8a530Spatrick       loc[-2] = 0x81;
436ece8a530Spatrick       loc[-1] = 0xc0 | reg;
437ece8a530Spatrick     }
438ece8a530Spatrick   } else {
439bb684c34Spatrick     assert(rel.type == R_386_TLS_GOTIE);
440ece8a530Spatrick     if (loc[-2] == 0x8b) {
441ece8a530Spatrick       // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg"
442ece8a530Spatrick       loc[-2] = 0xc7;
443ece8a530Spatrick       loc[-1] = 0xc0 | reg;
444ece8a530Spatrick     } else {
445ece8a530Spatrick       // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg"
446ece8a530Spatrick       loc[-2] = 0x8d;
447ece8a530Spatrick       loc[-1] = 0x80 | (reg << 3) | reg;
448ece8a530Spatrick     }
449ece8a530Spatrick   }
450ece8a530Spatrick   write32le(loc, val);
451ece8a530Spatrick }
452ece8a530Spatrick 
relaxTlsLdToLe(uint8_t * loc,const Relocation & rel,uint64_t val)453*dfe94b16Srobert static void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) {
454bb684c34Spatrick   if (rel.type == R_386_TLS_LDO_32) {
455ece8a530Spatrick     write32le(loc, val);
456ece8a530Spatrick     return;
457ece8a530Spatrick   }
458ece8a530Spatrick 
459*dfe94b16Srobert   if (loc[4] == 0xe8) {
460ece8a530Spatrick     // Convert
461*dfe94b16Srobert     //   leal x(%reg),%eax
462*dfe94b16Srobert     //   call ___tls_get_addr@plt
463ece8a530Spatrick     // to
464ece8a530Spatrick     const uint8_t inst[] = {
465ece8a530Spatrick         0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax
466ece8a530Spatrick         0x90,                               // nop
467ece8a530Spatrick         0x8d, 0x74, 0x26, 0x00,             // leal 0(%esi,1),%esi
468ece8a530Spatrick     };
469ece8a530Spatrick     memcpy(loc - 2, inst, sizeof(inst));
470*dfe94b16Srobert     return;
471*dfe94b16Srobert   }
472*dfe94b16Srobert 
473*dfe94b16Srobert   // Convert
474*dfe94b16Srobert   //   leal x(%reg),%eax
475*dfe94b16Srobert   //   call *___tls_get_addr@got(%reg)
476*dfe94b16Srobert   // to
477*dfe94b16Srobert   const uint8_t inst[] = {
478*dfe94b16Srobert       0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax
479*dfe94b16Srobert       0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00, // leal (%esi),%esi
480*dfe94b16Srobert   };
481*dfe94b16Srobert   memcpy(loc - 2, inst, sizeof(inst));
482*dfe94b16Srobert }
483*dfe94b16Srobert 
relocateAlloc(InputSectionBase & sec,uint8_t * buf) const484*dfe94b16Srobert void X86::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
485*dfe94b16Srobert   uint64_t secAddr = sec.getOutputSection()->addr;
486*dfe94b16Srobert   if (auto *s = dyn_cast<InputSection>(&sec))
487*dfe94b16Srobert     secAddr += s->outSecOff;
488*dfe94b16Srobert   for (const Relocation &rel : sec.relocs()) {
489*dfe94b16Srobert     uint8_t *loc = buf + rel.offset;
490*dfe94b16Srobert     const uint64_t val = SignExtend64(
491*dfe94b16Srobert         sec.getRelocTargetVA(sec.file, rel.type, rel.addend,
492*dfe94b16Srobert                              secAddr + rel.offset, *rel.sym, rel.expr),
493*dfe94b16Srobert         32);
494*dfe94b16Srobert     switch (rel.expr) {
495*dfe94b16Srobert     case R_RELAX_TLS_GD_TO_IE_GOTPLT:
496*dfe94b16Srobert       relaxTlsGdToIe(loc, rel, val);
497*dfe94b16Srobert       continue;
498*dfe94b16Srobert     case R_RELAX_TLS_GD_TO_LE:
499*dfe94b16Srobert     case R_RELAX_TLS_GD_TO_LE_NEG:
500*dfe94b16Srobert       relaxTlsGdToLe(loc, rel, val);
501*dfe94b16Srobert       continue;
502*dfe94b16Srobert     case R_RELAX_TLS_LD_TO_LE:
503*dfe94b16Srobert       relaxTlsLdToLe(loc, rel, val);
504*dfe94b16Srobert       break;
505*dfe94b16Srobert     case R_RELAX_TLS_IE_TO_LE:
506*dfe94b16Srobert       relaxTlsIeToLe(loc, rel, val);
507*dfe94b16Srobert       continue;
508*dfe94b16Srobert     default:
509*dfe94b16Srobert       relocate(loc, rel, val);
510*dfe94b16Srobert       break;
511*dfe94b16Srobert     }
512*dfe94b16Srobert   }
513ece8a530Spatrick }
514ece8a530Spatrick 
515ece8a530Spatrick // If Intel Indirect Branch Tracking is enabled, we have to emit special PLT
516ece8a530Spatrick // entries containing endbr32 instructions. A PLT entry will be split into two
517ece8a530Spatrick // parts, one in .plt.sec (writePlt), and the other in .plt (writeIBTPlt).
518ece8a530Spatrick namespace {
519ece8a530Spatrick class IntelIBT : public X86 {
520ece8a530Spatrick public:
521ece8a530Spatrick   IntelIBT();
522ece8a530Spatrick   void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
523ece8a530Spatrick   void writePlt(uint8_t *buf, const Symbol &sym,
524ece8a530Spatrick                 uint64_t pltEntryAddr) const override;
525ece8a530Spatrick   void writeIBTPlt(uint8_t *buf, size_t numEntries) const override;
526ece8a530Spatrick 
527ece8a530Spatrick   static const unsigned IBTPltHeaderSize = 16;
528ece8a530Spatrick };
529ece8a530Spatrick } // namespace
530ece8a530Spatrick 
IntelIBT()531ece8a530Spatrick IntelIBT::IntelIBT() { pltHeaderSize = 0; }
532ece8a530Spatrick 
writeGotPlt(uint8_t * buf,const Symbol & s) const533ece8a530Spatrick void IntelIBT::writeGotPlt(uint8_t *buf, const Symbol &s) const {
534ece8a530Spatrick   uint64_t va =
535*dfe94b16Srobert       in.ibtPlt->getVA() + IBTPltHeaderSize + s.getPltIdx() * pltEntrySize;
536ece8a530Spatrick   write32le(buf, va);
537ece8a530Spatrick }
538ece8a530Spatrick 
writePlt(uint8_t * buf,const Symbol & sym,uint64_t) const539ece8a530Spatrick void IntelIBT::writePlt(uint8_t *buf, const Symbol &sym,
540ece8a530Spatrick                         uint64_t /*pltEntryAddr*/) const {
541ece8a530Spatrick   if (config->isPic) {
542ece8a530Spatrick     const uint8_t inst[] = {
543ece8a530Spatrick         0xf3, 0x0f, 0x1e, 0xfb,       // endbr32
544ece8a530Spatrick         0xff, 0xa3, 0,    0,    0, 0, // jmp *name@GOT(%ebx)
545ece8a530Spatrick         0x66, 0x0f, 0x1f, 0x44, 0, 0, // nop
546ece8a530Spatrick     };
547ece8a530Spatrick     memcpy(buf, inst, sizeof(inst));
548ece8a530Spatrick     write32le(buf + 6, sym.getGotPltVA() - in.gotPlt->getVA());
549ece8a530Spatrick     return;
550ece8a530Spatrick   }
551ece8a530Spatrick 
552ece8a530Spatrick   const uint8_t inst[] = {
553ece8a530Spatrick       0xf3, 0x0f, 0x1e, 0xfb,       // endbr32
554ece8a530Spatrick       0xff, 0x25, 0,    0,    0, 0, // jmp *foo@GOT
555ece8a530Spatrick       0x66, 0x0f, 0x1f, 0x44, 0, 0, // nop
556ece8a530Spatrick   };
557ece8a530Spatrick   memcpy(buf, inst, sizeof(inst));
558ece8a530Spatrick   write32le(buf + 6, sym.getGotPltVA());
559ece8a530Spatrick }
560ece8a530Spatrick 
writeIBTPlt(uint8_t * buf,size_t numEntries) const561ece8a530Spatrick void IntelIBT::writeIBTPlt(uint8_t *buf, size_t numEntries) const {
562ece8a530Spatrick   writePltHeader(buf);
563ece8a530Spatrick   buf += IBTPltHeaderSize;
564ece8a530Spatrick 
565ece8a530Spatrick   const uint8_t inst[] = {
566ece8a530Spatrick       0xf3, 0x0f, 0x1e, 0xfb,    // endbr32
567ece8a530Spatrick       0x68, 0,    0,    0,    0, // pushl $reloc_offset
568ece8a530Spatrick       0xe9, 0,    0,    0,    0, // jmpq .PLT0@PC
569ece8a530Spatrick       0x66, 0x90,                // nop
570ece8a530Spatrick   };
571ece8a530Spatrick 
572ece8a530Spatrick   for (size_t i = 0; i < numEntries; ++i) {
573ece8a530Spatrick     memcpy(buf, inst, sizeof(inst));
574ece8a530Spatrick     write32le(buf + 5, i * sizeof(object::ELF32LE::Rel));
575ece8a530Spatrick     write32le(buf + 10, -pltHeaderSize - sizeof(inst) * i - 30);
576ece8a530Spatrick     buf += sizeof(inst);
577ece8a530Spatrick   }
578ece8a530Spatrick }
579ece8a530Spatrick 
580ece8a530Spatrick namespace {
581ece8a530Spatrick class RetpolinePic : public X86 {
582ece8a530Spatrick public:
583ece8a530Spatrick   RetpolinePic();
584ece8a530Spatrick   void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
585ece8a530Spatrick   void writePltHeader(uint8_t *buf) const override;
586ece8a530Spatrick   void writePlt(uint8_t *buf, const Symbol &sym,
587ece8a530Spatrick                 uint64_t pltEntryAddr) const override;
588ece8a530Spatrick };
589ece8a530Spatrick 
590ece8a530Spatrick class RetpolineNoPic : public X86 {
591ece8a530Spatrick public:
592ece8a530Spatrick   RetpolineNoPic();
593ece8a530Spatrick   void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
594ece8a530Spatrick   void writePltHeader(uint8_t *buf) const override;
595ece8a530Spatrick   void writePlt(uint8_t *buf, const Symbol &sym,
596ece8a530Spatrick                 uint64_t pltEntryAddr) const override;
597ece8a530Spatrick };
598ece8a530Spatrick } // namespace
599ece8a530Spatrick 
RetpolinePic()600ece8a530Spatrick RetpolinePic::RetpolinePic() {
601ece8a530Spatrick   pltHeaderSize = 48;
602ece8a530Spatrick   pltEntrySize = 32;
603ece8a530Spatrick   ipltEntrySize = 32;
604ece8a530Spatrick }
605ece8a530Spatrick 
writeGotPlt(uint8_t * buf,const Symbol & s) const606ece8a530Spatrick void RetpolinePic::writeGotPlt(uint8_t *buf, const Symbol &s) const {
607ece8a530Spatrick   write32le(buf, s.getPltVA() + 17);
608ece8a530Spatrick }
609ece8a530Spatrick 
writePltHeader(uint8_t * buf) const610ece8a530Spatrick void RetpolinePic::writePltHeader(uint8_t *buf) const {
611ece8a530Spatrick   const uint8_t insn[] = {
612ece8a530Spatrick       0xff, 0xb3, 4,    0,    0,    0,          // 0:    pushl 4(%ebx)
613ece8a530Spatrick       0x50,                                     // 6:    pushl %eax
614ece8a530Spatrick       0x8b, 0x83, 8,    0,    0,    0,          // 7:    mov 8(%ebx), %eax
615ece8a530Spatrick       0xe8, 0x0e, 0x00, 0x00, 0x00,             // d:    call next
616ece8a530Spatrick       0xf3, 0x90,                               // 12: loop: pause
617ece8a530Spatrick       0x0f, 0xae, 0xe8,                         // 14:   lfence
618ece8a530Spatrick       0xeb, 0xf9,                               // 17:   jmp loop
619ece8a530Spatrick       0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19:   int3; .align 16
620ece8a530Spatrick       0x89, 0x0c, 0x24,                         // 20: next: mov %ecx, (%esp)
621ece8a530Spatrick       0x8b, 0x4c, 0x24, 0x04,                   // 23:   mov 0x4(%esp), %ecx
622ece8a530Spatrick       0x89, 0x44, 0x24, 0x04,                   // 27:   mov %eax ,0x4(%esp)
623ece8a530Spatrick       0x89, 0xc8,                               // 2b:   mov %ecx, %eax
624ece8a530Spatrick       0x59,                                     // 2d:   pop %ecx
625ece8a530Spatrick       0xc3,                                     // 2e:   ret
626ece8a530Spatrick       0xcc,                                     // 2f:   int3; padding
627ece8a530Spatrick   };
628ece8a530Spatrick   memcpy(buf, insn, sizeof(insn));
629ece8a530Spatrick }
630ece8a530Spatrick 
writePlt(uint8_t * buf,const Symbol & sym,uint64_t pltEntryAddr) const631ece8a530Spatrick void RetpolinePic::writePlt(uint8_t *buf, const Symbol &sym,
632ece8a530Spatrick                             uint64_t pltEntryAddr) const {
633*dfe94b16Srobert   unsigned relOff = in.relaPlt->entsize * sym.getPltIdx();
634ece8a530Spatrick   const uint8_t insn[] = {
635ece8a530Spatrick       0x50,                            // pushl %eax
636ece8a530Spatrick       0x8b, 0x83, 0,    0,    0,    0, // mov foo@GOT(%ebx), %eax
637ece8a530Spatrick       0xe8, 0,    0,    0,    0,       // call plt+0x20
638ece8a530Spatrick       0xe9, 0,    0,    0,    0,       // jmp plt+0x12
639ece8a530Spatrick       0x68, 0,    0,    0,    0,       // pushl $reloc_offset
640ece8a530Spatrick       0xe9, 0,    0,    0,    0,       // jmp plt+0
641ece8a530Spatrick       0xcc, 0xcc, 0xcc, 0xcc, 0xcc,    // int3; padding
642ece8a530Spatrick   };
643ece8a530Spatrick   memcpy(buf, insn, sizeof(insn));
644ece8a530Spatrick 
645ece8a530Spatrick   uint32_t ebx = in.gotPlt->getVA();
646ece8a530Spatrick   unsigned off = pltEntryAddr - in.plt->getVA();
647ece8a530Spatrick   write32le(buf + 3, sym.getGotPltVA() - ebx);
648ece8a530Spatrick   write32le(buf + 8, -off - 12 + 32);
649ece8a530Spatrick   write32le(buf + 13, -off - 17 + 18);
650ece8a530Spatrick   write32le(buf + 18, relOff);
651ece8a530Spatrick   write32le(buf + 23, -off - 27);
652ece8a530Spatrick }
653ece8a530Spatrick 
RetpolineNoPic()654ece8a530Spatrick RetpolineNoPic::RetpolineNoPic() {
655ece8a530Spatrick   pltHeaderSize = 48;
656ece8a530Spatrick   pltEntrySize = 32;
657ece8a530Spatrick   ipltEntrySize = 32;
658ece8a530Spatrick }
659ece8a530Spatrick 
writeGotPlt(uint8_t * buf,const Symbol & s) const660ece8a530Spatrick void RetpolineNoPic::writeGotPlt(uint8_t *buf, const Symbol &s) const {
661ece8a530Spatrick   write32le(buf, s.getPltVA() + 16);
662ece8a530Spatrick }
663ece8a530Spatrick 
writePltHeader(uint8_t * buf) const664ece8a530Spatrick void RetpolineNoPic::writePltHeader(uint8_t *buf) const {
665ece8a530Spatrick   const uint8_t insn[] = {
666ece8a530Spatrick       0xff, 0x35, 0,    0,    0,    0, // 0:    pushl GOTPLT+4
667ece8a530Spatrick       0x50,                            // 6:    pushl %eax
668ece8a530Spatrick       0xa1, 0,    0,    0,    0,       // 7:    mov GOTPLT+8, %eax
669ece8a530Spatrick       0xe8, 0x0f, 0x00, 0x00, 0x00,    // c:    call next
670ece8a530Spatrick       0xf3, 0x90,                      // 11: loop: pause
671ece8a530Spatrick       0x0f, 0xae, 0xe8,                // 13:   lfence
672ece8a530Spatrick       0xeb, 0xf9,                      // 16:   jmp loop
673ece8a530Spatrick       0xcc, 0xcc, 0xcc, 0xcc, 0xcc,    // 18:   int3
674ece8a530Spatrick       0xcc, 0xcc, 0xcc,                // 1f:   int3; .align 16
675ece8a530Spatrick       0x89, 0x0c, 0x24,                // 20: next: mov %ecx, (%esp)
676ece8a530Spatrick       0x8b, 0x4c, 0x24, 0x04,          // 23:   mov 0x4(%esp), %ecx
677ece8a530Spatrick       0x89, 0x44, 0x24, 0x04,          // 27:   mov %eax ,0x4(%esp)
678ece8a530Spatrick       0x89, 0xc8,                      // 2b:   mov %ecx, %eax
679ece8a530Spatrick       0x59,                            // 2d:   pop %ecx
680ece8a530Spatrick       0xc3,                            // 2e:   ret
681ece8a530Spatrick       0xcc,                            // 2f:   int3; padding
682ece8a530Spatrick   };
683ece8a530Spatrick   memcpy(buf, insn, sizeof(insn));
684ece8a530Spatrick 
685ece8a530Spatrick   uint32_t gotPlt = in.gotPlt->getVA();
686ece8a530Spatrick   write32le(buf + 2, gotPlt + 4);
687ece8a530Spatrick   write32le(buf + 8, gotPlt + 8);
688ece8a530Spatrick }
689ece8a530Spatrick 
writePlt(uint8_t * buf,const Symbol & sym,uint64_t pltEntryAddr) const690ece8a530Spatrick void RetpolineNoPic::writePlt(uint8_t *buf, const Symbol &sym,
691ece8a530Spatrick                               uint64_t pltEntryAddr) const {
692*dfe94b16Srobert   unsigned relOff = in.relaPlt->entsize * sym.getPltIdx();
693ece8a530Spatrick   const uint8_t insn[] = {
694ece8a530Spatrick       0x50,                         // 0:  pushl %eax
695ece8a530Spatrick       0xa1, 0,    0,    0,    0,    // 1:  mov foo_in_GOT, %eax
696ece8a530Spatrick       0xe8, 0,    0,    0,    0,    // 6:  call plt+0x20
697ece8a530Spatrick       0xe9, 0,    0,    0,    0,    // b:  jmp plt+0x11
698ece8a530Spatrick       0x68, 0,    0,    0,    0,    // 10: pushl $reloc_offset
699ece8a530Spatrick       0xe9, 0,    0,    0,    0,    // 15: jmp plt+0
700ece8a530Spatrick       0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding
701ece8a530Spatrick       0xcc,                         // 1f: int3; padding
702ece8a530Spatrick   };
703ece8a530Spatrick   memcpy(buf, insn, sizeof(insn));
704ece8a530Spatrick 
705ece8a530Spatrick   unsigned off = pltEntryAddr - in.plt->getVA();
706ece8a530Spatrick   write32le(buf + 2, sym.getGotPltVA());
707ece8a530Spatrick   write32le(buf + 7, -off - 11 + 32);
708ece8a530Spatrick   write32le(buf + 12, -off - 16 + 17);
709ece8a530Spatrick   write32le(buf + 17, relOff);
710ece8a530Spatrick   write32le(buf + 22, -off - 26);
711ece8a530Spatrick }
712ece8a530Spatrick 
getX86TargetInfo()713bb684c34Spatrick TargetInfo *elf::getX86TargetInfo() {
714ece8a530Spatrick   if (config->zRetpolineplt) {
715ece8a530Spatrick     if (config->isPic) {
716ece8a530Spatrick       static RetpolinePic t;
717ece8a530Spatrick       return &t;
718ece8a530Spatrick     }
719ece8a530Spatrick     static RetpolineNoPic t;
720ece8a530Spatrick     return &t;
721ece8a530Spatrick   }
722ece8a530Spatrick 
723ece8a530Spatrick   if (config->andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT) {
724ece8a530Spatrick     static IntelIBT t;
725ece8a530Spatrick     return &t;
726ece8a530Spatrick   }
727ece8a530Spatrick 
728ece8a530Spatrick   static X86 t;
729ece8a530Spatrick   return &t;
730ece8a530Spatrick }
731