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