1 | //===-- PPCELFObjectWriter.cpp - PPC 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/PPCFixupKinds.h" |
10 | #include "MCTargetDesc/PPCMCAsmInfo.h" |
11 | #include "MCTargetDesc/PPCMCTargetDesc.h" |
12 | #include "llvm/MC/MCContext.h" |
13 | #include "llvm/MC/MCELFObjectWriter.h" |
14 | #include "llvm/MC/MCExpr.h" |
15 | #include "llvm/MC/MCObjectWriter.h" |
16 | #include "llvm/MC/MCSymbolELF.h" |
17 | #include "llvm/MC/MCValue.h" |
18 | #include "llvm/Support/ErrorHandling.h" |
19 | |
20 | using namespace llvm; |
21 | |
22 | namespace { |
23 | class PPCELFObjectWriter : public MCELFObjectTargetWriter { |
24 | public: |
25 | PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI); |
26 | |
27 | protected: |
28 | unsigned getRelocType(const MCFixup &Fixup, const MCValue &Target, |
29 | bool IsPCRel) const override; |
30 | |
31 | bool needsRelocateWithSymbol(const MCValue &, unsigned Type) const override; |
32 | }; |
33 | } |
34 | |
35 | PPCELFObjectWriter::PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI) |
36 | : MCELFObjectTargetWriter(Is64Bit, OSABI, |
37 | Is64Bit ? ELF::EM_PPC64 : ELF::EM_PPC, |
38 | /*HasRelocationAddend*/ true) {} |
39 | |
40 | unsigned PPCELFObjectWriter::getRelocType(const MCFixup &Fixup, |
41 | const MCValue &Target, |
42 | bool IsPCRel) const { |
43 | SMLoc Loc = Fixup.getValue()->getLoc(); |
44 | auto Spec = static_cast<PPCMCExpr::Specifier>(Target.getSpecifier()); |
45 | switch (Spec) { |
46 | case PPC::S_DTPMOD: |
47 | case PPC::S_DTPREL: |
48 | case PPC::S_DTPREL_HA: |
49 | case PPC::S_DTPREL_HI: |
50 | case PPC::S_DTPREL_HIGH: |
51 | case PPC::S_DTPREL_HIGHA: |
52 | case PPC::S_DTPREL_HIGHER: |
53 | case PPC::S_DTPREL_HIGHERA: |
54 | case PPC::S_DTPREL_HIGHEST: |
55 | case PPC::S_DTPREL_HIGHESTA: |
56 | case PPC::S_DTPREL_LO: |
57 | case PPC::S_GOT_DTPREL: |
58 | case PPC::S_GOT_DTPREL_HA: |
59 | case PPC::S_GOT_DTPREL_HI: |
60 | case PPC::S_GOT_DTPREL_LO: |
61 | case PPC::S_GOT_TLSGD: |
62 | case PPC::S_GOT_TLSGD_HA: |
63 | case PPC::S_GOT_TLSGD_HI: |
64 | case PPC::S_GOT_TLSGD_LO: |
65 | case PPC::S_GOT_TLSGD_PCREL: |
66 | case PPC::S_GOT_TLSLD: |
67 | case PPC::S_GOT_TLSLD_HA: |
68 | case PPC::S_GOT_TLSLD_HI: |
69 | case PPC::S_GOT_TLSLD_LO: |
70 | case PPC::S_GOT_TPREL: |
71 | case PPC::S_GOT_TPREL_HA: |
72 | case PPC::S_GOT_TPREL_HI: |
73 | case PPC::S_GOT_TPREL_LO: |
74 | case PPC::S_GOT_TPREL_PCREL: |
75 | case PPC::S_TLS: |
76 | case PPC::S_TLSGD: |
77 | case PPC::S_TLSLD: |
78 | case PPC::S_TLS_PCREL: |
79 | case PPC::S_TPREL: |
80 | case PPC::S_TPREL_HA: |
81 | case PPC::S_TPREL_HI: |
82 | case PPC::S_TPREL_HIGH: |
83 | case PPC::S_TPREL_HIGHA: |
84 | case PPC::S_TPREL_HIGHER: |
85 | case PPC::S_TPREL_HIGHERA: |
86 | case PPC::S_TPREL_HIGHEST: |
87 | case PPC::S_TPREL_HIGHESTA: |
88 | case PPC::S_TPREL_LO: |
89 | if (auto *SA = Target.getAddSym()) |
90 | cast<MCSymbolELF>(Val: SA)->setType(ELF::STT_TLS); |
91 | break; |
92 | default: |
93 | break; |
94 | } |
95 | |
96 | // determine the type of the relocation |
97 | unsigned Type = 0; |
98 | if (IsPCRel) { |
99 | switch (Fixup.getTargetKind()) { |
100 | default: |
101 | llvm_unreachable("Unimplemented" ); |
102 | case PPC::fixup_ppc_br24: |
103 | case PPC::fixup_ppc_br24abs: |
104 | case PPC::fixup_ppc_br24_notoc: |
105 | switch (Spec) { |
106 | default: |
107 | reportError(L: Loc, Msg: "unsupported relocation type" ); |
108 | break; |
109 | case PPC::S_None: |
110 | Type = ELF::R_PPC_REL24; |
111 | break; |
112 | case PPC::S_PLT: |
113 | Type = ELF::R_PPC_PLTREL24; |
114 | break; |
115 | case PPC::S_LOCAL: |
116 | Type = ELF::R_PPC_LOCAL24PC; |
117 | break; |
118 | case PPC::S_NOTOC: |
119 | Type = ELF::R_PPC64_REL24_NOTOC; |
120 | break; |
121 | } |
122 | break; |
123 | case PPC::fixup_ppc_brcond14: |
124 | case PPC::fixup_ppc_brcond14abs: |
125 | Type = ELF::R_PPC_REL14; |
126 | break; |
127 | case PPC::fixup_ppc_half16: |
128 | switch (Spec) { |
129 | default: |
130 | reportError(L: Loc, Msg: "unsupported relocation type" ); |
131 | return ELF::R_PPC_NONE; |
132 | case PPC::S_None: |
133 | return ELF::R_PPC_REL16; |
134 | case PPC::S_LO: |
135 | return ELF::R_PPC_REL16_LO; |
136 | case PPC::S_HI: |
137 | return ELF::R_PPC_REL16_HI; |
138 | case PPC::S_HA: |
139 | return ELF::R_PPC_REL16_HA; |
140 | } |
141 | break; |
142 | case PPC::fixup_ppc_half16ds: |
143 | case PPC::fixup_ppc_half16dq: |
144 | reportError(L: Loc, Msg: "unsupported relocation type" ); |
145 | break; |
146 | case PPC::fixup_ppc_pcrel34: |
147 | switch (Spec) { |
148 | default: |
149 | reportError(L: Loc, Msg: "unsupported relocation type" ); |
150 | break; |
151 | case PPC::S_PCREL: |
152 | Type = ELF::R_PPC64_PCREL34; |
153 | break; |
154 | case PPC::S_GOT_PCREL: |
155 | Type = ELF::R_PPC64_GOT_PCREL34; |
156 | break; |
157 | case PPC::S_GOT_TLSGD_PCREL: |
158 | Type = ELF::R_PPC64_GOT_TLSGD_PCREL34; |
159 | break; |
160 | case PPC::S_GOT_TLSLD_PCREL: |
161 | Type = ELF::R_PPC64_GOT_TLSLD_PCREL34; |
162 | break; |
163 | case PPC::S_GOT_TPREL_PCREL: |
164 | Type = ELF::R_PPC64_GOT_TPREL_PCREL34; |
165 | break; |
166 | } |
167 | break; |
168 | case FK_Data_4: |
169 | Type = ELF::R_PPC_REL32; |
170 | break; |
171 | case FK_Data_8: |
172 | Type = ELF::R_PPC64_REL64; |
173 | break; |
174 | } |
175 | } else { |
176 | switch (Fixup.getTargetKind()) { |
177 | default: llvm_unreachable("invalid fixup kind!" ); |
178 | case PPC::fixup_ppc_br24abs: |
179 | Type = ELF::R_PPC_ADDR24; |
180 | break; |
181 | case PPC::fixup_ppc_brcond14abs: |
182 | Type = ELF::R_PPC_ADDR14; // XXX: or BRNTAKEN?_ |
183 | break; |
184 | case PPC::fixup_ppc_half16: |
185 | switch (Spec) { |
186 | default: |
187 | reportError(L: Loc, Msg: "unsupported relocation type" ); |
188 | break; |
189 | case PPC::S_LO: |
190 | return ELF::R_PPC_ADDR16_LO; |
191 | case PPC::S_HI: |
192 | return ELF::R_PPC_ADDR16_HI; |
193 | case PPC::S_HA: |
194 | return ELF::R_PPC_ADDR16_HA; |
195 | case PPC::S_HIGH: |
196 | return ELF::R_PPC64_ADDR16_HIGH; |
197 | case PPC::S_HIGHA: |
198 | return ELF::R_PPC64_ADDR16_HIGHA; |
199 | case PPC::S_HIGHER: |
200 | return ELF::R_PPC64_ADDR16_HIGHER; |
201 | case PPC::S_HIGHERA: |
202 | return ELF::R_PPC64_ADDR16_HIGHERA; |
203 | case PPC::S_HIGHEST: |
204 | return ELF::R_PPC64_ADDR16_HIGHEST; |
205 | case PPC::S_HIGHESTA: |
206 | return ELF::R_PPC64_ADDR16_HIGHESTA; |
207 | |
208 | case PPC::S_None: |
209 | Type = ELF::R_PPC_ADDR16; |
210 | break; |
211 | case PPC::S_GOT: |
212 | Type = ELF::R_PPC_GOT16; |
213 | break; |
214 | case PPC::S_GOT_LO: |
215 | Type = ELF::R_PPC_GOT16_LO; |
216 | break; |
217 | case PPC::S_GOT_HI: |
218 | Type = ELF::R_PPC_GOT16_HI; |
219 | break; |
220 | case PPC::S_GOT_HA: |
221 | Type = ELF::R_PPC_GOT16_HA; |
222 | break; |
223 | case PPC::S_TOC: |
224 | Type = ELF::R_PPC64_TOC16; |
225 | break; |
226 | case PPC::S_TOC_LO: |
227 | Type = ELF::R_PPC64_TOC16_LO; |
228 | break; |
229 | case PPC::S_TOC_HI: |
230 | Type = ELF::R_PPC64_TOC16_HI; |
231 | break; |
232 | case PPC::S_TOC_HA: |
233 | Type = ELF::R_PPC64_TOC16_HA; |
234 | break; |
235 | case PPC::S_TPREL: |
236 | Type = ELF::R_PPC_TPREL16; |
237 | break; |
238 | case PPC::S_TPREL_LO: |
239 | Type = ELF::R_PPC_TPREL16_LO; |
240 | break; |
241 | case PPC::S_TPREL_HI: |
242 | Type = ELF::R_PPC_TPREL16_HI; |
243 | break; |
244 | case PPC::S_TPREL_HA: |
245 | Type = ELF::R_PPC_TPREL16_HA; |
246 | break; |
247 | case PPC::S_TPREL_HIGH: |
248 | Type = ELF::R_PPC64_TPREL16_HIGH; |
249 | break; |
250 | case PPC::S_TPREL_HIGHA: |
251 | Type = ELF::R_PPC64_TPREL16_HIGHA; |
252 | break; |
253 | case PPC::S_TPREL_HIGHER: |
254 | Type = ELF::R_PPC64_TPREL16_HIGHER; |
255 | break; |
256 | case PPC::S_TPREL_HIGHERA: |
257 | Type = ELF::R_PPC64_TPREL16_HIGHERA; |
258 | break; |
259 | case PPC::S_TPREL_HIGHEST: |
260 | Type = ELF::R_PPC64_TPREL16_HIGHEST; |
261 | break; |
262 | case PPC::S_TPREL_HIGHESTA: |
263 | Type = ELF::R_PPC64_TPREL16_HIGHESTA; |
264 | break; |
265 | case PPC::S_DTPREL: |
266 | Type = ELF::R_PPC64_DTPREL16; |
267 | break; |
268 | case PPC::S_DTPREL_LO: |
269 | Type = ELF::R_PPC64_DTPREL16_LO; |
270 | break; |
271 | case PPC::S_DTPREL_HI: |
272 | Type = ELF::R_PPC64_DTPREL16_HI; |
273 | break; |
274 | case PPC::S_DTPREL_HA: |
275 | Type = ELF::R_PPC64_DTPREL16_HA; |
276 | break; |
277 | case PPC::S_DTPREL_HIGH: |
278 | Type = ELF::R_PPC64_DTPREL16_HIGH; |
279 | break; |
280 | case PPC::S_DTPREL_HIGHA: |
281 | Type = ELF::R_PPC64_DTPREL16_HIGHA; |
282 | break; |
283 | case PPC::S_DTPREL_HIGHER: |
284 | Type = ELF::R_PPC64_DTPREL16_HIGHER; |
285 | break; |
286 | case PPC::S_DTPREL_HIGHERA: |
287 | Type = ELF::R_PPC64_DTPREL16_HIGHERA; |
288 | break; |
289 | case PPC::S_DTPREL_HIGHEST: |
290 | Type = ELF::R_PPC64_DTPREL16_HIGHEST; |
291 | break; |
292 | case PPC::S_DTPREL_HIGHESTA: |
293 | Type = ELF::R_PPC64_DTPREL16_HIGHESTA; |
294 | break; |
295 | case PPC::S_GOT_TLSGD: |
296 | if (is64Bit()) |
297 | Type = ELF::R_PPC64_GOT_TLSGD16; |
298 | else |
299 | Type = ELF::R_PPC_GOT_TLSGD16; |
300 | break; |
301 | case PPC::S_GOT_TLSGD_LO: |
302 | Type = ELF::R_PPC64_GOT_TLSGD16_LO; |
303 | break; |
304 | case PPC::S_GOT_TLSGD_HI: |
305 | Type = ELF::R_PPC64_GOT_TLSGD16_HI; |
306 | break; |
307 | case PPC::S_GOT_TLSGD_HA: |
308 | Type = ELF::R_PPC64_GOT_TLSGD16_HA; |
309 | break; |
310 | case PPC::S_GOT_TLSLD: |
311 | if (is64Bit()) |
312 | Type = ELF::R_PPC64_GOT_TLSLD16; |
313 | else |
314 | Type = ELF::R_PPC_GOT_TLSLD16; |
315 | break; |
316 | case PPC::S_GOT_TLSLD_LO: |
317 | Type = ELF::R_PPC64_GOT_TLSLD16_LO; |
318 | break; |
319 | case PPC::S_GOT_TLSLD_HI: |
320 | Type = ELF::R_PPC64_GOT_TLSLD16_HI; |
321 | break; |
322 | case PPC::S_GOT_TLSLD_HA: |
323 | Type = ELF::R_PPC64_GOT_TLSLD16_HA; |
324 | break; |
325 | case PPC::S_GOT_TPREL: |
326 | /* We don't have R_PPC64_GOT_TPREL16, but since GOT offsets |
327 | are always 4-aligned, we can use R_PPC64_GOT_TPREL16_DS. */ |
328 | Type = ELF::R_PPC64_GOT_TPREL16_DS; |
329 | break; |
330 | case PPC::S_GOT_TPREL_LO: |
331 | /* We don't have R_PPC64_GOT_TPREL16_LO, but since GOT offsets |
332 | are always 4-aligned, we can use R_PPC64_GOT_TPREL16_LO_DS. */ |
333 | Type = ELF::R_PPC64_GOT_TPREL16_LO_DS; |
334 | break; |
335 | case PPC::S_GOT_TPREL_HI: |
336 | Type = ELF::R_PPC64_GOT_TPREL16_HI; |
337 | break; |
338 | case PPC::S_GOT_DTPREL: |
339 | /* We don't have R_PPC64_GOT_DTPREL16, but since GOT offsets |
340 | are always 4-aligned, we can use R_PPC64_GOT_DTPREL16_DS. */ |
341 | Type = ELF::R_PPC64_GOT_DTPREL16_DS; |
342 | break; |
343 | case PPC::S_GOT_DTPREL_LO: |
344 | /* We don't have R_PPC64_GOT_DTPREL16_LO, but since GOT offsets |
345 | are always 4-aligned, we can use R_PPC64_GOT_DTPREL16_LO_DS. */ |
346 | Type = ELF::R_PPC64_GOT_DTPREL16_LO_DS; |
347 | break; |
348 | case PPC::S_GOT_TPREL_HA: |
349 | Type = ELF::R_PPC64_GOT_TPREL16_HA; |
350 | break; |
351 | case PPC::S_GOT_DTPREL_HI: |
352 | Type = ELF::R_PPC64_GOT_DTPREL16_HI; |
353 | break; |
354 | case PPC::S_GOT_DTPREL_HA: |
355 | Type = ELF::R_PPC64_GOT_DTPREL16_HA; |
356 | break; |
357 | } |
358 | break; |
359 | case PPC::fixup_ppc_half16ds: |
360 | case PPC::fixup_ppc_half16dq: |
361 | switch (Spec) { |
362 | default: |
363 | reportError(L: Loc, Msg: "unsupported relocation type" ); |
364 | break; |
365 | case PPC::S_LO: |
366 | return ELF::R_PPC64_ADDR16_LO_DS; |
367 | case PPC::S_None: |
368 | Type = ELF::R_PPC64_ADDR16_DS; |
369 | break; |
370 | case PPC::S_GOT: |
371 | Type = ELF::R_PPC64_GOT16_DS; |
372 | break; |
373 | case PPC::S_GOT_LO: |
374 | Type = ELF::R_PPC64_GOT16_LO_DS; |
375 | break; |
376 | case PPC::S_TOC: |
377 | Type = ELF::R_PPC64_TOC16_DS; |
378 | break; |
379 | case PPC::S_TOC_LO: |
380 | Type = ELF::R_PPC64_TOC16_LO_DS; |
381 | break; |
382 | case PPC::S_TPREL: |
383 | Type = ELF::R_PPC64_TPREL16_DS; |
384 | break; |
385 | case PPC::S_TPREL_LO: |
386 | Type = ELF::R_PPC64_TPREL16_LO_DS; |
387 | break; |
388 | case PPC::S_DTPREL: |
389 | Type = ELF::R_PPC64_DTPREL16_DS; |
390 | break; |
391 | case PPC::S_DTPREL_LO: |
392 | Type = ELF::R_PPC64_DTPREL16_LO_DS; |
393 | break; |
394 | case PPC::S_GOT_TPREL: |
395 | Type = ELF::R_PPC64_GOT_TPREL16_DS; |
396 | break; |
397 | case PPC::S_GOT_TPREL_LO: |
398 | Type = ELF::R_PPC64_GOT_TPREL16_LO_DS; |
399 | break; |
400 | case PPC::S_GOT_DTPREL: |
401 | Type = ELF::R_PPC64_GOT_DTPREL16_DS; |
402 | break; |
403 | case PPC::S_GOT_DTPREL_LO: |
404 | Type = ELF::R_PPC64_GOT_DTPREL16_LO_DS; |
405 | break; |
406 | } |
407 | break; |
408 | case PPC::fixup_ppc_nofixup: |
409 | switch (Spec) { |
410 | default: |
411 | reportError(L: Loc, Msg: "unsupported relocation type" ); |
412 | break; |
413 | case PPC::S_TLSGD: |
414 | if (is64Bit()) |
415 | Type = ELF::R_PPC64_TLSGD; |
416 | else |
417 | Type = ELF::R_PPC_TLSGD; |
418 | break; |
419 | case PPC::S_TLSLD: |
420 | if (is64Bit()) |
421 | Type = ELF::R_PPC64_TLSLD; |
422 | else |
423 | Type = ELF::R_PPC_TLSLD; |
424 | break; |
425 | case PPC::S_TLS: |
426 | if (is64Bit()) |
427 | Type = ELF::R_PPC64_TLS; |
428 | else |
429 | Type = ELF::R_PPC_TLS; |
430 | break; |
431 | case PPC::S_TLS_PCREL: |
432 | Type = ELF::R_PPC64_TLS; |
433 | break; |
434 | } |
435 | break; |
436 | case PPC::fixup_ppc_imm34: |
437 | switch (Spec) { |
438 | default: |
439 | reportError(L: Loc, Msg: "unsupported relocation type" ); |
440 | break; |
441 | case PPC::S_DTPREL: |
442 | Type = ELF::R_PPC64_DTPREL34; |
443 | break; |
444 | case PPC::S_TPREL: |
445 | Type = ELF::R_PPC64_TPREL34; |
446 | break; |
447 | } |
448 | break; |
449 | case FK_Data_8: |
450 | switch (Spec) { |
451 | default: |
452 | reportError(L: Loc, Msg: "unsupported relocation type" ); |
453 | break; |
454 | case PPC::S_TOCBASE: |
455 | Type = ELF::R_PPC64_TOC; |
456 | break; |
457 | case PPC::S_None: |
458 | Type = ELF::R_PPC64_ADDR64; |
459 | break; |
460 | case PPC::S_DTPMOD: |
461 | Type = ELF::R_PPC64_DTPMOD64; |
462 | break; |
463 | case PPC::S_TPREL: |
464 | Type = ELF::R_PPC64_TPREL64; |
465 | break; |
466 | case PPC::S_DTPREL: |
467 | Type = ELF::R_PPC64_DTPREL64; |
468 | break; |
469 | } |
470 | break; |
471 | case FK_Data_4: |
472 | switch (Spec) { |
473 | case PPC::S_DTPREL: |
474 | Type = ELF::R_PPC_DTPREL32; |
475 | break; |
476 | default: |
477 | Type = ELF::R_PPC_ADDR32; |
478 | } |
479 | break; |
480 | case FK_Data_2: |
481 | Type = ELF::R_PPC_ADDR16; |
482 | break; |
483 | } |
484 | } |
485 | return Type; |
486 | } |
487 | |
488 | bool PPCELFObjectWriter::needsRelocateWithSymbol(const MCValue &V, |
489 | unsigned Type) const { |
490 | switch (Type) { |
491 | default: |
492 | return false; |
493 | |
494 | case ELF::R_PPC_REL24: |
495 | case ELF::R_PPC64_REL24_NOTOC: { |
496 | // If the target symbol has a local entry point, we must keep the |
497 | // target symbol to preserve that information for the linker. |
498 | // The "other" values are stored in the last 6 bits of the second byte. |
499 | // The traditional defines for STO values assume the full byte and thus |
500 | // the shift to pack it. |
501 | unsigned Other = cast<MCSymbolELF>(Val: V.getAddSym())->getOther() << 2; |
502 | return (Other & ELF::STO_PPC64_LOCAL_MASK) != 0; |
503 | } |
504 | |
505 | case ELF::R_PPC64_GOT16: |
506 | case ELF::R_PPC64_GOT16_DS: |
507 | case ELF::R_PPC64_GOT16_LO: |
508 | case ELF::R_PPC64_GOT16_LO_DS: |
509 | case ELF::R_PPC64_GOT16_HI: |
510 | case ELF::R_PPC64_GOT16_HA: |
511 | return true; |
512 | } |
513 | } |
514 | |
515 | std::unique_ptr<MCObjectTargetWriter> |
516 | llvm::createPPCELFObjectWriter(bool Is64Bit, uint8_t OSABI) { |
517 | return std::make_unique<PPCELFObjectWriter>(args&: Is64Bit, args&: OSABI); |
518 | } |
519 | |