Coverage Report

Created: 2019-05-22 02:55

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/ELF/Arch/X86.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- X86.cpp ------------------------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "InputFiles.h"
10
#include "Symbols.h"
11
#include "SyntheticSections.h"
12
#include "Target.h"
13
#include "lld/Common/ErrorHandler.h"
14
#include "llvm/Support/Endian.h"
15
16
using namespace llvm;
17
using namespace llvm::support::endian;
18
using namespace llvm::ELF;
19
using namespace lld;
20
using namespace lld::elf;
21
22
namespace {
23
class X86 : public TargetInfo {
24
public:
25
  X86();
26
  int getTlsGdRelaxSkip(RelType Type) const override;
27
  RelExpr getRelExpr(RelType Type, const Symbol &S,
28
                     const uint8_t *Loc) const override;
29
  int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override;
30
  void writeGotPltHeader(uint8_t *Buf) const override;
31
  RelType getDynRel(RelType Type) const override;
32
  void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
33
  void writeIgotPlt(uint8_t *Buf, const Symbol &S) const override;
34
  void writePltHeader(uint8_t *Buf) const override;
35
  void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
36
                int32_t Index, unsigned RelOff) const override;
37
  void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
38
39
  RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
40
                          RelExpr Expr) const override;
41
  void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
42
  void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
43
  void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
44
  void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
45
};
46
} // namespace
47
48
69
X86::X86() {
49
69
  CopyRel = R_386_COPY;
50
69
  GotRel = R_386_GLOB_DAT;
51
69
  NoneRel = R_386_NONE;
52
69
  PltRel = R_386_JUMP_SLOT;
53
69
  IRelativeRel = R_386_IRELATIVE;
54
69
  RelativeRel = R_386_RELATIVE;
55
69
  TlsGotRel = R_386_TLS_TPOFF;
56
69
  TlsModuleIndexRel = R_386_TLS_DTPMOD32;
57
69
  TlsOffsetRel = R_386_TLS_DTPOFF32;
58
69
  GotEntrySize = 4;
59
69
  GotPltEntrySize = 4;
60
69
  PltEntrySize = 16;
61
69
  PltHeaderSize = 16;
62
69
  TrapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3
63
69
64
69
  // Align to the non-PAE large page size (known as a superpage or huge page).
65
69
  // FreeBSD automatically promotes large, superpage-aligned allocations.
66
69
  DefaultImageBase = 0x400000;
67
69
}
68
69
0
int X86::getTlsGdRelaxSkip(RelType Type) const {
70
0
  return 2;
71
0
}
72
73
RelExpr X86::getRelExpr(RelType Type, const Symbol &S,
74
99
                        const uint8_t *Loc) const {
75
99
  // There are 4 different TLS variable models with varying degrees of
76
99
  // flexibility and performance. LocalExec and InitialExec models are fast but
77
99
  // less-flexible models. If they are in use, we set DF_STATIC_TLS flag in the
78
99
  // dynamic section to let runtime know about that.
79
99
  if (Type == R_386_TLS_LE || 
Type == R_386_TLS_LE_3296
||
Type == R_386_TLS_IE91
||
80
99
      
Type == R_386_TLS_GOTIE90
)
81
12
    Config->HasStaticTlsModel = true;
82
99
83
99
  switch (Type) {
84
99
  case R_386_8:
85
24
  case R_386_16:
86
24
  case R_386_32:
87
24
    return R_ABS;
88
24
  case R_386_TLS_LDO_32:
89
3
    return R_DTPREL;
90
24
  case R_386_TLS_GD:
91
2
    return R_TLSGD_GOTPLT;
92
24
  case R_386_TLS_LDM:
93
3
    return R_TLSLD_GOTPLT;
94
24
  case R_386_PLT32:
95
22
    return R_PLT_PC;
96
24
  case R_386_PC8:
97
14
  case R_386_PC16:
98
14
  case R_386_PC32:
99
14
    return R_PC;
100
14
  case R_386_GOTPC:
101
4
    return R_GOTPLTONLY_PC;
102
14
  case R_386_TLS_IE:
103
1
    return R_GOT;
104
14
  case R_386_GOT32:
105
13
  case R_386_GOT32X:
106
13
    // These relocations are arguably mis-designed because their calculations
107
13
    // depend on the instructions they are applied to. This is bad because we
108
13
    // usually don't care about whether the target section contains valid
109
13
    // machine instructions or not. But this is part of the documented ABI, so
110
13
    // we had to implement as the standard requires.
111
13
    //
112
13
    // x86 does not support PC-relative data access. Therefore, in order to
113
13
    // access GOT contents, a GOT address needs to be known at link-time
114
13
    // (which means non-PIC) or compilers have to emit code to get a GOT
115
13
    // address at runtime (which means code is position-independent but
116
13
    // compilers need to emit extra code for each GOT access.) This decision
117
13
    // is made at compile-time. In the latter case, compilers emit code to
118
13
    // load an GOT address to a register, which is usually %ebx.
119
13
    //
120
13
    // So, there are two ways to refer to symbol foo's GOT entry: foo@GOT or
121
13
    // foo@GOT(%ebx).
122
13
    //
123
13
    // foo@GOT is not usable in PIC. If we are creating a PIC output and if we
124
13
    // find such relocation, we should report an error. foo@GOT is resolved to
125
13
    // an *absolute* address of foo's GOT entry, because both GOT address and
126
13
    // foo's offset are known. In other words, it's G + A.
127
13
    //
128
13
    // foo@GOT(%ebx) needs to be resolved to a *relative* offset from a GOT to
129
13
    // foo's GOT entry in the table, because GOT address is not known but foo's
130
13
    // offset in the table is known. It's G + A - GOT.
131
13
    //
132
13
    // It's unfortunate that compilers emit the same relocation for these
133
13
    // different use cases. In order to distinguish them, we have to read a
134
13
    // machine instruction.
135
13
    //
136
13
    // The following code implements it. We assume that Loc[0] is the first byte
137
13
    // of a displacement or an immediate field of a valid machine
138
13
    // instruction. That means a ModRM byte is at Loc[-1]. By taking a look at
139
13
    // the byte, we can determine whether the instruction uses the operand as an
140
13
    // absolute address (R_GOT) or a register-relative address (R_GOTPLT).
141
13
    return (Loc[-1] & 0xc7) == 0x5 ? 
R_GOT3
:
R_GOTPLT10
;
142
13
  case R_386_TLS_GOTIE:
143
3
    return R_GOTPLT;
144
13
  case R_386_GOTOFF:
145
0
    return R_GOTPLTREL;
146
13
  case R_386_TLS_LE:
147
3
    return R_TLS;
148
13
  case R_386_TLS_LE_32:
149
5
    return R_NEG_TLS;
150
13
  case R_386_NONE:
151
0
    return R_NONE;
152
13
  default:
153
2
    error(getErrorLocation(Loc) + "unknown relocation (" + Twine(Type) +
154
2
          ") against symbol " + toString(S));
155
2
    return R_NONE;
156
99
  }
157
99
}
158
159
RelExpr X86::adjustRelaxExpr(RelType Type, const uint8_t *Data,
160
                             RelExpr Expr) const {
161
  switch (Expr) {
162
  default:
163
    return Expr;
164
  case R_RELAX_TLS_GD_TO_IE:
165
    return R_RELAX_TLS_GD_TO_IE_GOTPLT;
166
  case R_RELAX_TLS_GD_TO_LE:
167
    return R_RELAX_TLS_GD_TO_LE_NEG;
168
  }
169
}
170
171
16
void X86::writeGotPltHeader(uint8_t *Buf) const {
172
16
  write32le(Buf, In.Dynamic->getVA());
173
16
}
174
175
9
void X86::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
176
9
  // Entries in .got.plt initially points back to the corresponding
177
9
  // PLT entries with a fixed offset to skip the first instruction.
178
9
  write32le(Buf, S.getPltVA() + 6);
179
9
}
180
181
4
void X86::writeIgotPlt(uint8_t *Buf, const Symbol &S) const {
182
4
  // An x86 entry is the address of the ifunc resolver function.
183
4
  write32le(Buf, S.getVA());
184
4
}
185
186
13
RelType X86::getDynRel(RelType Type) const {
187
13
  if (Type == R_386_TLS_LE)
188
3
    return R_386_TLS_TPOFF;
189
10
  if (Type == R_386_TLS_LE_32)
190
3
    return R_386_TLS_TPOFF32;
191
7
  return Type;
192
7
}
193
194
7
void X86::writePltHeader(uint8_t *Buf) const {
195
7
  if (Config->Pic) {
196
4
    const uint8_t V[] = {
197
4
        0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx)
198
4
        0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx)
199
4
        0x90, 0x90, 0x90, 0x90              // nop
200
4
    };
201
4
    memcpy(Buf, V, sizeof(V));
202
4
    return;
203
4
  }
204
3
205
3
  const uint8_t PltData[] = {
206
3
      0xff, 0x35, 0, 0, 0, 0, // pushl (GOTPLT+4)
207
3
      0xff, 0x25, 0, 0, 0, 0, // jmp *(GOTPLT+8)
208
3
      0x90, 0x90, 0x90, 0x90, // nop
209
3
  };
210
3
  memcpy(Buf, PltData, sizeof(PltData));
211
3
  uint32_t GotPlt = In.GotPlt->getVA();
212
3
  write32le(Buf + 2, GotPlt + 4);
213
3
  write32le(Buf + 8, GotPlt + 8);
214
3
}
215
216
void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
217
                   uint64_t PltEntryAddr, int32_t Index,
218
13
                   unsigned RelOff) const {
219
13
  if (Config->Pic) {
220
5
    const uint8_t Inst[] = {
221
5
        0xff, 0xa3, 0, 0, 0, 0, // jmp *foo@GOT(%ebx)
222
5
        0x68, 0,    0, 0, 0,    // pushl $reloc_offset
223
5
        0xe9, 0,    0, 0, 0,    // jmp .PLT0@PC
224
5
    };
225
5
    memcpy(Buf, Inst, sizeof(Inst));
226
5
    write32le(Buf + 2, GotPltEntryAddr - In.GotPlt->getVA());
227
8
  } else {
228
8
    const uint8_t Inst[] = {
229
8
        0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT
230
8
        0x68, 0,    0, 0, 0,    // pushl $reloc_offset
231
8
        0xe9, 0,    0, 0, 0,    // jmp .PLT0@PC
232
8
    };
233
8
    memcpy(Buf, Inst, sizeof(Inst));
234
8
    write32le(Buf + 2, GotPltEntryAddr);
235
8
  }
236
13
237
13
  write32le(Buf + 7, RelOff);
238
13
  write32le(Buf + 12, -PltHeaderSize - PltEntrySize * Index - 16);
239
13
}
240
241
101
int64_t X86::getImplicitAddend(const uint8_t *Buf, RelType Type) const {
242
101
  switch (Type) {
243
101
  case R_386_8:
244
3
  case R_386_PC8:
245
3
    return SignExtend64<8>(*Buf);
246
8
  case R_386_16:
247
8
  case R_386_PC16:
248
8
    return SignExtend64<16>(read16le(Buf));
249
74
  case R_386_32:
250
74
  case R_386_GOT32:
251
74
  case R_386_GOT32X:
252
74
  case R_386_GOTOFF:
253
74
  case R_386_GOTPC:
254
74
  case R_386_PC32:
255
74
  case R_386_PLT32:
256
74
  case R_386_TLS_LDO_32:
257
74
  case R_386_TLS_LE:
258
74
    return SignExtend64<32>(read32le(Buf));
259
74
  default:
260
16
    return 0;
261
101
  }
262
101
}
263
264
89
void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
265
89
  switch (Type) {
266
89
  case R_386_8:
267
2
    // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are
268
2
    // being used for some 16-bit programs such as boot loaders, so
269
2
    // we want to support them.
270
2
    checkIntUInt(Loc, Val, 8, Type);
271
2
    *Loc = Val;
272
2
    break;
273
89
  case R_386_PC8:
274
1
    checkInt(Loc, Val, 8, Type);
275
1
    *Loc = Val;
276
1
    break;
277
89
  case R_386_16:
278
4
    checkIntUInt(Loc, Val, 16, Type);
279
4
    write16le(Loc, Val);
280
4
    break;
281
89
  case R_386_PC16:
282
4
    // R_386_PC16 is normally used with 16 bit code. In that situation
283
4
    // the PC is 16 bits, just like the addend. This means that it can
284
4
    // point from any 16 bit address to any other if the possibility
285
4
    // of wrapping is included.
286
4
    // The only restriction we have to check then is that the destination
287
4
    // address fits in 16 bits. That is impossible to do here. The problem is
288
4
    // that we are passed the final value, which already had the
289
4
    // current location subtracted from it.
290
4
    // We just check that Val fits in 17 bits. This misses some cases, but
291
4
    // should have no false positives.
292
4
    checkInt(Loc, Val, 17, Type);
293
4
    write16le(Loc, Val);
294
4
    break;
295
89
  case R_386_32:
296
78
  case R_386_GLOB_DAT:
297
78
  case R_386_GOT32:
298
78
  case R_386_GOT32X:
299
78
  case R_386_GOTOFF:
300
78
  case R_386_GOTPC:
301
78
  case R_386_PC32:
302
78
  case R_386_PLT32:
303
78
  case R_386_RELATIVE:
304
78
  case R_386_TLS_DTPMOD32:
305
78
  case R_386_TLS_DTPOFF32:
306
78
  case R_386_TLS_GD:
307
78
  case R_386_TLS_GOTIE:
308
78
  case R_386_TLS_IE:
309
78
  case R_386_TLS_LDM:
310
78
  case R_386_TLS_LDO_32:
311
78
  case R_386_TLS_LE:
312
78
  case R_386_TLS_LE_32:
313
78
  case R_386_TLS_TPOFF:
314
78
  case R_386_TLS_TPOFF32:
315
78
    checkInt(Loc, Val, 32, Type);
316
78
    write32le(Loc, Val);
317
78
    break;
318
78
  default:
319
0
    llvm_unreachable("unknown relocation");
320
89
  }
321
89
}
322
323
0
void X86::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
324
0
  // Convert
325
0
  //   leal x@tlsgd(, %ebx, 1),
326
0
  //   call __tls_get_addr@plt
327
0
  // to
328
0
  //   movl %gs:0,%eax
329
0
  //   subl $x@ntpoff,%eax
330
0
  const uint8_t Inst[] = {
331
0
      0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
332
0
      0x81, 0xe8, 0, 0, 0, 0,             // subl Val(%ebx), %eax
333
0
  };
334
0
  memcpy(Loc - 3, Inst, sizeof(Inst));
335
0
  write32le(Loc + 5, Val);
336
0
}
337
338
0
void X86::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
339
0
  // Convert
340
0
  //   leal x@tlsgd(, %ebx, 1),
341
0
  //   call __tls_get_addr@plt
342
0
  // to
343
0
  //   movl %gs:0, %eax
344
0
  //   addl x@gotntpoff(%ebx), %eax
345
0
  const uint8_t Inst[] = {
346
0
      0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax
347
0
      0x03, 0x83, 0, 0, 0, 0,             // addl Val(%ebx), %eax
348
0
  };
349
0
  memcpy(Loc - 3, Inst, sizeof(Inst));
350
0
  write32le(Loc + 5, Val);
351
0
}
352
353
// In some conditions, relocations can be optimized to avoid using GOT.
354
// This function does that for Initial Exec to Local Exec case.
355
0
void X86::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
356
0
  // Ulrich's document section 6.2 says that @gotntpoff can
357
0
  // be used with MOVL or ADDL instructions.
358
0
  // @indntpoff is similar to @gotntpoff, but for use in
359
0
  // position dependent code.
360
0
  uint8_t Reg = (Loc[-1] >> 3) & 7;
361
0
362
0
  if (Type == R_386_TLS_IE) {
363
0
    if (Loc[-1] == 0xa1) {
364
0
      // "movl foo@indntpoff,%eax" -> "movl $foo,%eax"
365
0
      // This case is different from the generic case below because
366
0
      // this is a 5 byte instruction while below is 6 bytes.
367
0
      Loc[-1] = 0xb8;
368
0
    } else if (Loc[-2] == 0x8b) {
369
0
      // "movl foo@indntpoff,%reg" -> "movl $foo,%reg"
370
0
      Loc[-2] = 0xc7;
371
0
      Loc[-1] = 0xc0 | Reg;
372
0
    } else {
373
0
      // "addl foo@indntpoff,%reg" -> "addl $foo,%reg"
374
0
      Loc[-2] = 0x81;
375
0
      Loc[-1] = 0xc0 | Reg;
376
0
    }
377
0
  } else {
378
0
    assert(Type == R_386_TLS_GOTIE);
379
0
    if (Loc[-2] == 0x8b) {
380
0
      // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg"
381
0
      Loc[-2] = 0xc7;
382
0
      Loc[-1] = 0xc0 | Reg;
383
0
    } else {
384
0
      // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg"
385
0
      Loc[-2] = 0x8d;
386
0
      Loc[-1] = 0x80 | (Reg << 3) | Reg;
387
0
    }
388
0
  }
389
0
  write32le(Loc, Val);
390
0
}
391
392
0
void X86::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
393
0
  if (Type == R_386_TLS_LDO_32) {
394
0
    write32le(Loc, Val);
395
0
    return;
396
0
  }
397
0
398
0
  // Convert
399
0
  //   leal foo(%reg),%eax
400
0
  //   call ___tls_get_addr
401
0
  // to
402
0
  //   movl %gs:0,%eax
403
0
  //   nop
404
0
  //   leal 0(%esi,1),%esi
405
0
  const uint8_t Inst[] = {
406
0
      0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax
407
0
      0x90,                               // nop
408
0
      0x8d, 0x74, 0x26, 0x00,             // leal 0(%esi,1),%esi
409
0
  };
410
0
  memcpy(Loc - 2, Inst, sizeof(Inst));
411
0
}
412
413
namespace {
414
class RetpolinePic : public X86 {
415
public:
416
  RetpolinePic();
417
  void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
418
  void writePltHeader(uint8_t *Buf) const override;
419
  void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
420
                int32_t Index, unsigned RelOff) const override;
421
};
422
423
class RetpolineNoPic : public X86 {
424
public:
425
  RetpolineNoPic();
426
  void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
427
  void writePltHeader(uint8_t *Buf) const override;
428
  void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
429
                int32_t Index, unsigned RelOff) const override;
430
};
431
} // namespace
432
433
2
RetpolinePic::RetpolinePic() {
434
2
  PltHeaderSize = 48;
435
2
  PltEntrySize = 32;
436
2
}
437
438
4
void RetpolinePic::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
439
4
  write32le(Buf, S.getPltVA() + 17);
440
4
}
441
442
2
void RetpolinePic::writePltHeader(uint8_t *Buf) const {
443
2
  const uint8_t Insn[] = {
444
2
      0xff, 0xb3, 4,    0,    0,    0,          // 0:    pushl 4(%ebx)
445
2
      0x50,                                     // 6:    pushl %eax
446
2
      0x8b, 0x83, 8,    0,    0,    0,          // 7:    mov 8(%ebx), %eax
447
2
      0xe8, 0x0e, 0x00, 0x00, 0x00,             // d:    call next
448
2
      0xf3, 0x90,                               // 12: loop: pause
449
2
      0x0f, 0xae, 0xe8,                         // 14:   lfence
450
2
      0xeb, 0xf9,                               // 17:   jmp loop
451
2
      0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19:   int3; .align 16
452
2
      0x89, 0x0c, 0x24,                         // 20: next: mov %ecx, (%esp)
453
2
      0x8b, 0x4c, 0x24, 0x04,                   // 23:   mov 0x4(%esp), %ecx
454
2
      0x89, 0x44, 0x24, 0x04,                   // 27:   mov %eax ,0x4(%esp)
455
2
      0x89, 0xc8,                               // 2b:   mov %ecx, %eax
456
2
      0x59,                                     // 2d:   pop %ecx
457
2
      0xc3,                                     // 2e:   ret
458
2
      0xcc,                                     // 2f:   int3; padding
459
2
  };
460
2
  memcpy(Buf, Insn, sizeof(Insn));
461
2
}
462
463
void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
464
                            uint64_t PltEntryAddr, int32_t Index,
465
4
                            unsigned RelOff) const {
466
4
  const uint8_t Insn[] = {
467
4
      0x50,                            // pushl %eax
468
4
      0x8b, 0x83, 0,    0,    0,    0, // mov foo@GOT(%ebx), %eax
469
4
      0xe8, 0,    0,    0,    0,       // call plt+0x20
470
4
      0xe9, 0,    0,    0,    0,       // jmp plt+0x12
471
4
      0x68, 0,    0,    0,    0,       // pushl $reloc_offset
472
4
      0xe9, 0,    0,    0,    0,       // jmp plt+0
473
4
      0xcc, 0xcc, 0xcc, 0xcc, 0xcc,    // int3; padding
474
4
  };
475
4
  memcpy(Buf, Insn, sizeof(Insn));
476
4
477
4
  uint32_t Ebx = In.GotPlt->getVA();
478
4
  unsigned Off = PltHeaderSize + PltEntrySize * Index;
479
4
  write32le(Buf + 3, GotPltEntryAddr - Ebx);
480
4
  write32le(Buf + 8, -Off - 12 + 32);
481
4
  write32le(Buf + 13, -Off - 17 + 18);
482
4
  write32le(Buf + 18, RelOff);
483
4
  write32le(Buf + 23, -Off - 27);
484
4
}
485
486
2
RetpolineNoPic::RetpolineNoPic() {
487
2
  PltHeaderSize = 48;
488
2
  PltEntrySize = 32;
489
2
}
490
491
4
void RetpolineNoPic::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
492
4
  write32le(Buf, S.getPltVA() + 16);
493
4
}
494
495
2
void RetpolineNoPic::writePltHeader(uint8_t *Buf) const {
496
2
  const uint8_t Insn[] = {
497
2
      0xff, 0x35, 0,    0,    0,    0, // 0:    pushl GOTPLT+4
498
2
      0x50,                            // 6:    pushl %eax
499
2
      0xa1, 0,    0,    0,    0,       // 7:    mov GOTPLT+8, %eax
500
2
      0xe8, 0x0f, 0x00, 0x00, 0x00,    // c:    call next
501
2
      0xf3, 0x90,                      // 11: loop: pause
502
2
      0x0f, 0xae, 0xe8,                // 13:   lfence
503
2
      0xeb, 0xf9,                      // 16:   jmp loop
504
2
      0xcc, 0xcc, 0xcc, 0xcc, 0xcc,    // 18:   int3
505
2
      0xcc, 0xcc, 0xcc,                // 1f:   int3; .align 16
506
2
      0x89, 0x0c, 0x24,                // 20: next: mov %ecx, (%esp)
507
2
      0x8b, 0x4c, 0x24, 0x04,          // 23:   mov 0x4(%esp), %ecx
508
2
      0x89, 0x44, 0x24, 0x04,          // 27:   mov %eax ,0x4(%esp)
509
2
      0x89, 0xc8,                      // 2b:   mov %ecx, %eax
510
2
      0x59,                            // 2d:   pop %ecx
511
2
      0xc3,                            // 2e:   ret
512
2
      0xcc,                            // 2f:   int3; padding
513
2
  };
514
2
  memcpy(Buf, Insn, sizeof(Insn));
515
2
516
2
  uint32_t GotPlt = In.GotPlt->getVA();
517
2
  write32le(Buf + 2, GotPlt + 4);
518
2
  write32le(Buf + 8, GotPlt + 8);
519
2
}
520
521
void RetpolineNoPic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
522
                              uint64_t PltEntryAddr, int32_t Index,
523
4
                              unsigned RelOff) const {
524
4
  const uint8_t Insn[] = {
525
4
      0x50,                         // 0:  pushl %eax
526
4
      0xa1, 0,    0,    0,    0,    // 1:  mov foo_in_GOT, %eax
527
4
      0xe8, 0,    0,    0,    0,    // 6:  call plt+0x20
528
4
      0xe9, 0,    0,    0,    0,    // b:  jmp plt+0x11
529
4
      0x68, 0,    0,    0,    0,    // 10: pushl $reloc_offset
530
4
      0xe9, 0,    0,    0,    0,    // 15: jmp plt+0
531
4
      0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding
532
4
      0xcc,                         // 1f: int3; padding
533
4
  };
534
4
  memcpy(Buf, Insn, sizeof(Insn));
535
4
536
4
  unsigned Off = PltHeaderSize + PltEntrySize * Index;
537
4
  write32le(Buf + 2, GotPltEntryAddr);
538
4
  write32le(Buf + 7, -Off - 11 + 32);
539
4
  write32le(Buf + 12, -Off - 16 + 17);
540
4
  write32le(Buf + 17, RelOff);
541
4
  write32le(Buf + 22, -Off - 26);
542
4
}
543
544
69
TargetInfo *elf::getX86TargetInfo() {
545
69
  if (Config->ZRetpolineplt) {
546
4
    if (Config->Pic) {
547
2
      static RetpolinePic T;
548
2
      return &T;
549
2
    }
550
2
    static RetpolineNoPic T;
551
2
    return &T;
552
2
  }
553
65
554
65
  static X86 T;
555
65
  return &T;
556
65
}