Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
35294 views
1
//===-- X86ELFObjectWriter.cpp - X86 ELF Writer ---------------------------===//
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 "MCTargetDesc/X86FixupKinds.h"
10
#include "MCTargetDesc/X86MCTargetDesc.h"
11
#include "llvm/BinaryFormat/ELF.h"
12
#include "llvm/MC/MCAsmInfo.h"
13
#include "llvm/MC/MCContext.h"
14
#include "llvm/MC/MCELFObjectWriter.h"
15
#include "llvm/MC/MCExpr.h"
16
#include "llvm/MC/MCFixup.h"
17
#include "llvm/MC/MCObjectWriter.h"
18
#include "llvm/MC/MCValue.h"
19
#include "llvm/Support/ErrorHandling.h"
20
#include <cassert>
21
#include <cstdint>
22
23
using namespace llvm;
24
25
namespace {
26
27
class X86ELFObjectWriter : public MCELFObjectTargetWriter {
28
public:
29
X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine);
30
~X86ELFObjectWriter() override = default;
31
32
protected:
33
unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
34
const MCFixup &Fixup, bool IsPCRel) const override;
35
};
36
37
} // end anonymous namespace
38
39
X86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI,
40
uint16_t EMachine)
41
: MCELFObjectTargetWriter(IsELF64, OSABI, EMachine,
42
// Only i386 and IAMCU use Rel instead of RelA.
43
/*HasRelocationAddend*/
44
(EMachine != ELF::EM_386) &&
45
(EMachine != ELF::EM_IAMCU)) {}
46
47
enum X86_64RelType { RT64_NONE, RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 };
48
49
static X86_64RelType getType64(MCFixupKind Kind,
50
MCSymbolRefExpr::VariantKind &Modifier,
51
bool &IsPCRel) {
52
switch (unsigned(Kind)) {
53
default:
54
llvm_unreachable("Unimplemented");
55
case FK_NONE:
56
return RT64_NONE;
57
case X86::reloc_global_offset_table8:
58
Modifier = MCSymbolRefExpr::VK_GOT;
59
IsPCRel = true;
60
return RT64_64;
61
case FK_Data_8:
62
return RT64_64;
63
case X86::reloc_signed_4byte:
64
case X86::reloc_signed_4byte_relax:
65
if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel)
66
return RT64_32S;
67
return RT64_32;
68
case X86::reloc_global_offset_table:
69
Modifier = MCSymbolRefExpr::VK_GOT;
70
IsPCRel = true;
71
return RT64_32;
72
case FK_Data_4:
73
case FK_PCRel_4:
74
case X86::reloc_riprel_4byte:
75
case X86::reloc_riprel_4byte_relax:
76
case X86::reloc_riprel_4byte_relax_rex:
77
case X86::reloc_riprel_4byte_movq_load:
78
return RT64_32;
79
case X86::reloc_branch_4byte_pcrel:
80
Modifier = MCSymbolRefExpr::VK_PLT;
81
return RT64_32;
82
case FK_PCRel_2:
83
case FK_Data_2:
84
return RT64_16;
85
case FK_PCRel_1:
86
case FK_Data_1:
87
return RT64_8;
88
}
89
}
90
91
static void checkIs32(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) {
92
if (Type != RT64_32)
93
Ctx.reportError(Loc,
94
"32 bit reloc applied to a field with a different size");
95
}
96
97
static void checkIs64(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) {
98
if (Type != RT64_64)
99
Ctx.reportError(Loc,
100
"64 bit reloc applied to a field with a different size");
101
}
102
103
static unsigned getRelocType64(MCContext &Ctx, SMLoc Loc,
104
MCSymbolRefExpr::VariantKind Modifier,
105
X86_64RelType Type, bool IsPCRel,
106
MCFixupKind Kind) {
107
switch (Modifier) {
108
default:
109
llvm_unreachable("Unimplemented");
110
case MCSymbolRefExpr::VK_None:
111
case MCSymbolRefExpr::VK_X86_ABS8:
112
switch (Type) {
113
case RT64_NONE:
114
if (Modifier == MCSymbolRefExpr::VK_None)
115
return ELF::R_X86_64_NONE;
116
llvm_unreachable("Unimplemented");
117
case RT64_64:
118
return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64;
119
case RT64_32:
120
return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32;
121
case RT64_32S:
122
return ELF::R_X86_64_32S;
123
case RT64_16:
124
return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16;
125
case RT64_8:
126
return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8;
127
}
128
llvm_unreachable("unexpected relocation type!");
129
case MCSymbolRefExpr::VK_GOT:
130
switch (Type) {
131
case RT64_64:
132
return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64;
133
case RT64_32:
134
return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32;
135
case RT64_32S:
136
case RT64_16:
137
case RT64_8:
138
case RT64_NONE:
139
llvm_unreachable("Unimplemented");
140
}
141
llvm_unreachable("unexpected relocation type!");
142
case MCSymbolRefExpr::VK_GOTOFF:
143
assert(!IsPCRel);
144
if (Type != RT64_64)
145
Ctx.reportError(Loc, "unsupported relocation type");
146
return ELF::R_X86_64_GOTOFF64;
147
case MCSymbolRefExpr::VK_TPOFF:
148
assert(!IsPCRel);
149
switch (Type) {
150
case RT64_64:
151
return ELF::R_X86_64_TPOFF64;
152
case RT64_32:
153
return ELF::R_X86_64_TPOFF32;
154
case RT64_32S:
155
case RT64_16:
156
case RT64_8:
157
case RT64_NONE:
158
llvm_unreachable("Unimplemented");
159
}
160
llvm_unreachable("unexpected relocation type!");
161
case MCSymbolRefExpr::VK_DTPOFF:
162
assert(!IsPCRel);
163
switch (Type) {
164
case RT64_64:
165
return ELF::R_X86_64_DTPOFF64;
166
case RT64_32:
167
return ELF::R_X86_64_DTPOFF32;
168
case RT64_32S:
169
case RT64_16:
170
case RT64_8:
171
case RT64_NONE:
172
llvm_unreachable("Unimplemented");
173
}
174
llvm_unreachable("unexpected relocation type!");
175
case MCSymbolRefExpr::VK_SIZE:
176
assert(!IsPCRel);
177
switch (Type) {
178
case RT64_64:
179
return ELF::R_X86_64_SIZE64;
180
case RT64_32:
181
return ELF::R_X86_64_SIZE32;
182
case RT64_32S:
183
case RT64_16:
184
case RT64_8:
185
case RT64_NONE:
186
llvm_unreachable("Unimplemented");
187
}
188
llvm_unreachable("unexpected relocation type!");
189
case MCSymbolRefExpr::VK_TLSCALL:
190
return ELF::R_X86_64_TLSDESC_CALL;
191
case MCSymbolRefExpr::VK_TLSDESC:
192
return ELF::R_X86_64_GOTPC32_TLSDESC;
193
case MCSymbolRefExpr::VK_TLSGD:
194
checkIs32(Ctx, Loc, Type);
195
return ELF::R_X86_64_TLSGD;
196
case MCSymbolRefExpr::VK_GOTTPOFF:
197
checkIs32(Ctx, Loc, Type);
198
return ELF::R_X86_64_GOTTPOFF;
199
case MCSymbolRefExpr::VK_TLSLD:
200
checkIs32(Ctx, Loc, Type);
201
return ELF::R_X86_64_TLSLD;
202
case MCSymbolRefExpr::VK_PLT:
203
checkIs32(Ctx, Loc, Type);
204
return ELF::R_X86_64_PLT32;
205
case MCSymbolRefExpr::VK_GOTPCREL:
206
checkIs32(Ctx, Loc, Type);
207
// Older versions of ld.bfd/ld.gold/lld
208
// do not support GOTPCRELX/REX_GOTPCRELX,
209
// and we want to keep back-compatibility.
210
if (!Ctx.getTargetOptions()->X86RelaxRelocations)
211
return ELF::R_X86_64_GOTPCREL;
212
switch (unsigned(Kind)) {
213
default:
214
return ELF::R_X86_64_GOTPCREL;
215
case X86::reloc_riprel_4byte_relax:
216
return ELF::R_X86_64_GOTPCRELX;
217
case X86::reloc_riprel_4byte_relax_rex:
218
case X86::reloc_riprel_4byte_movq_load:
219
return ELF::R_X86_64_REX_GOTPCRELX;
220
}
221
llvm_unreachable("unexpected relocation type!");
222
case MCSymbolRefExpr::VK_GOTPCREL_NORELAX:
223
checkIs32(Ctx, Loc, Type);
224
return ELF::R_X86_64_GOTPCREL;
225
case MCSymbolRefExpr::VK_X86_PLTOFF:
226
checkIs64(Ctx, Loc, Type);
227
return ELF::R_X86_64_PLTOFF64;
228
}
229
}
230
231
enum X86_32RelType { RT32_NONE, RT32_32, RT32_16, RT32_8 };
232
233
static unsigned getRelocType32(MCContext &Ctx, SMLoc Loc,
234
MCSymbolRefExpr::VariantKind Modifier,
235
X86_32RelType Type, bool IsPCRel,
236
MCFixupKind Kind) {
237
switch (Modifier) {
238
default:
239
llvm_unreachable("Unimplemented");
240
case MCSymbolRefExpr::VK_None:
241
case MCSymbolRefExpr::VK_X86_ABS8:
242
switch (Type) {
243
case RT32_NONE:
244
if (Modifier == MCSymbolRefExpr::VK_None)
245
return ELF::R_386_NONE;
246
llvm_unreachable("Unimplemented");
247
case RT32_32:
248
return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32;
249
case RT32_16:
250
return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16;
251
case RT32_8:
252
return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8;
253
}
254
llvm_unreachable("unexpected relocation type!");
255
case MCSymbolRefExpr::VK_GOT:
256
if (Type != RT32_32)
257
break;
258
if (IsPCRel)
259
return ELF::R_386_GOTPC;
260
// Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we
261
// want to maintain compatibility.
262
if (!Ctx.getTargetOptions()->X86RelaxRelocations)
263
return ELF::R_386_GOT32;
264
265
return Kind == MCFixupKind(X86::reloc_signed_4byte_relax)
266
? ELF::R_386_GOT32X
267
: ELF::R_386_GOT32;
268
case MCSymbolRefExpr::VK_GOTOFF:
269
assert(!IsPCRel);
270
if (Type != RT32_32)
271
break;
272
return ELF::R_386_GOTOFF;
273
case MCSymbolRefExpr::VK_TLSCALL:
274
return ELF::R_386_TLS_DESC_CALL;
275
case MCSymbolRefExpr::VK_TLSDESC:
276
return ELF::R_386_TLS_GOTDESC;
277
case MCSymbolRefExpr::VK_TPOFF:
278
if (Type != RT32_32)
279
break;
280
assert(!IsPCRel);
281
return ELF::R_386_TLS_LE_32;
282
case MCSymbolRefExpr::VK_DTPOFF:
283
if (Type != RT32_32)
284
break;
285
assert(!IsPCRel);
286
return ELF::R_386_TLS_LDO_32;
287
case MCSymbolRefExpr::VK_TLSGD:
288
if (Type != RT32_32)
289
break;
290
assert(!IsPCRel);
291
return ELF::R_386_TLS_GD;
292
case MCSymbolRefExpr::VK_GOTTPOFF:
293
if (Type != RT32_32)
294
break;
295
assert(!IsPCRel);
296
return ELF::R_386_TLS_IE_32;
297
case MCSymbolRefExpr::VK_PLT:
298
if (Type != RT32_32)
299
break;
300
return ELF::R_386_PLT32;
301
case MCSymbolRefExpr::VK_INDNTPOFF:
302
if (Type != RT32_32)
303
break;
304
assert(!IsPCRel);
305
return ELF::R_386_TLS_IE;
306
case MCSymbolRefExpr::VK_NTPOFF:
307
if (Type != RT32_32)
308
break;
309
assert(!IsPCRel);
310
return ELF::R_386_TLS_LE;
311
case MCSymbolRefExpr::VK_GOTNTPOFF:
312
if (Type != RT32_32)
313
break;
314
assert(!IsPCRel);
315
return ELF::R_386_TLS_GOTIE;
316
case MCSymbolRefExpr::VK_TLSLDM:
317
if (Type != RT32_32)
318
break;
319
assert(!IsPCRel);
320
return ELF::R_386_TLS_LDM;
321
}
322
Ctx.reportError(Loc, "unsupported relocation type");
323
return ELF::R_386_NONE;
324
}
325
326
unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
327
const MCFixup &Fixup,
328
bool IsPCRel) const {
329
MCFixupKind Kind = Fixup.getKind();
330
if (Kind >= FirstLiteralRelocationKind)
331
return Kind - FirstLiteralRelocationKind;
332
MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
333
X86_64RelType Type = getType64(Kind, Modifier, IsPCRel);
334
if (getEMachine() == ELF::EM_X86_64)
335
return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel, Kind);
336
337
assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) &&
338
"Unsupported ELF machine type.");
339
340
X86_32RelType RelType = RT32_NONE;
341
switch (Type) {
342
case RT64_NONE:
343
break;
344
case RT64_64:
345
Ctx.reportError(Fixup.getLoc(), "unsupported relocation type");
346
return ELF::R_386_NONE;
347
case RT64_32:
348
case RT64_32S:
349
RelType = RT32_32;
350
break;
351
case RT64_16:
352
RelType = RT32_16;
353
break;
354
case RT64_8:
355
RelType = RT32_8;
356
break;
357
}
358
return getRelocType32(Ctx, Fixup.getLoc(), Modifier, RelType, IsPCRel, Kind);
359
}
360
361
std::unique_ptr<MCObjectTargetWriter>
362
llvm::createX86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine) {
363
return std::make_unique<X86ELFObjectWriter>(IsELF64, OSABI, EMachine);
364
}
365
366