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