1 | //===- RelocationResolver.cpp ------------------------------------*- C++ -*-===// |
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 | // This file defines utilities to resolve relocations in object files. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/Object/RelocationResolver.h" |
14 | #include "llvm/ADT/Twine.h" |
15 | #include "llvm/BinaryFormat/COFF.h" |
16 | #include "llvm/BinaryFormat/ELF.h" |
17 | #include "llvm/BinaryFormat/MachO.h" |
18 | #include "llvm/BinaryFormat/Wasm.h" |
19 | #include "llvm/Object/ELFObjectFile.h" |
20 | #include "llvm/Object/ELFTypes.h" |
21 | #include "llvm/Object/ObjectFile.h" |
22 | #include "llvm/Object/SymbolicFile.h" |
23 | #include "llvm/Support/Casting.h" |
24 | #include "llvm/Support/Error.h" |
25 | #include "llvm/Support/ErrorHandling.h" |
26 | #include "llvm/TargetParser/Triple.h" |
27 | #include <cassert> |
28 | |
29 | namespace llvm { |
30 | namespace object { |
31 | |
32 | static int64_t getELFAddend(RelocationRef R) { |
33 | Expected<int64_t> AddendOrErr = ELFRelocationRef(R).getAddend(); |
34 | handleAllErrors(E: AddendOrErr.takeError(), Handlers: [](const ErrorInfoBase &EI) { |
35 | report_fatal_error(reason: Twine(EI.message())); |
36 | }); |
37 | return *AddendOrErr; |
38 | } |
39 | |
40 | static bool supportsX86_64(uint64_t Type) { |
41 | switch (Type) { |
42 | case ELF::R_X86_64_NONE: |
43 | case ELF::R_X86_64_64: |
44 | case ELF::R_X86_64_DTPOFF32: |
45 | case ELF::R_X86_64_DTPOFF64: |
46 | case ELF::R_X86_64_PC32: |
47 | case ELF::R_X86_64_PC64: |
48 | case ELF::R_X86_64_32: |
49 | case ELF::R_X86_64_32S: |
50 | return true; |
51 | default: |
52 | return false; |
53 | } |
54 | } |
55 | |
56 | static uint64_t resolveX86_64(uint64_t Type, uint64_t Offset, uint64_t S, |
57 | uint64_t LocData, int64_t Addend) { |
58 | switch (Type) { |
59 | case ELF::R_X86_64_NONE: |
60 | return LocData; |
61 | case ELF::R_X86_64_64: |
62 | case ELF::R_X86_64_DTPOFF32: |
63 | case ELF::R_X86_64_DTPOFF64: |
64 | return S + Addend; |
65 | case ELF::R_X86_64_PC32: |
66 | case ELF::R_X86_64_PC64: |
67 | return S + Addend - Offset; |
68 | case ELF::R_X86_64_32: |
69 | case ELF::R_X86_64_32S: |
70 | return (S + Addend) & 0xFFFFFFFF; |
71 | default: |
72 | llvm_unreachable("Invalid relocation type" ); |
73 | } |
74 | } |
75 | |
76 | static bool supportsAArch64(uint64_t Type) { |
77 | switch (Type) { |
78 | case ELF::R_AARCH64_ABS32: |
79 | case ELF::R_AARCH64_ABS64: |
80 | case ELF::R_AARCH64_PREL16: |
81 | case ELF::R_AARCH64_PREL32: |
82 | case ELF::R_AARCH64_PREL64: |
83 | return true; |
84 | default: |
85 | return false; |
86 | } |
87 | } |
88 | |
89 | static uint64_t resolveAArch64(uint64_t Type, uint64_t Offset, uint64_t S, |
90 | uint64_t /*LocData*/, int64_t Addend) { |
91 | switch (Type) { |
92 | case ELF::R_AARCH64_ABS32: |
93 | return (S + Addend) & 0xFFFFFFFF; |
94 | case ELF::R_AARCH64_ABS64: |
95 | return S + Addend; |
96 | case ELF::R_AARCH64_PREL16: |
97 | return (S + Addend - Offset) & 0xFFFF; |
98 | case ELF::R_AARCH64_PREL32: |
99 | return (S + Addend - Offset) & 0xFFFFFFFF; |
100 | case ELF::R_AARCH64_PREL64: |
101 | return S + Addend - Offset; |
102 | default: |
103 | llvm_unreachable("Invalid relocation type" ); |
104 | } |
105 | } |
106 | |
107 | static bool supportsBPF(uint64_t Type) { |
108 | switch (Type) { |
109 | case ELF::R_BPF_64_ABS32: |
110 | case ELF::R_BPF_64_ABS64: |
111 | return true; |
112 | default: |
113 | return false; |
114 | } |
115 | } |
116 | |
117 | static uint64_t resolveBPF(uint64_t Type, uint64_t Offset, uint64_t S, |
118 | uint64_t LocData, int64_t /*Addend*/) { |
119 | switch (Type) { |
120 | case ELF::R_BPF_64_ABS32: |
121 | return (S + LocData) & 0xFFFFFFFF; |
122 | case ELF::R_BPF_64_ABS64: |
123 | return S + LocData; |
124 | default: |
125 | llvm_unreachable("Invalid relocation type" ); |
126 | } |
127 | } |
128 | |
129 | static bool supportsMips64(uint64_t Type) { |
130 | switch (Type) { |
131 | case ELF::R_MIPS_32: |
132 | case ELF::R_MIPS_64: |
133 | case ELF::R_MIPS_TLS_DTPREL64: |
134 | case ELF::R_MIPS_PC32: |
135 | return true; |
136 | default: |
137 | return false; |
138 | } |
139 | } |
140 | |
141 | static uint64_t resolveMips64(uint64_t Type, uint64_t Offset, uint64_t S, |
142 | uint64_t /*LocData*/, int64_t Addend) { |
143 | switch (Type) { |
144 | case ELF::R_MIPS_32: |
145 | return (S + Addend) & 0xFFFFFFFF; |
146 | case ELF::R_MIPS_64: |
147 | return S + Addend; |
148 | case ELF::R_MIPS_TLS_DTPREL64: |
149 | return S + Addend - 0x8000; |
150 | case ELF::R_MIPS_PC32: |
151 | return S + Addend - Offset; |
152 | default: |
153 | llvm_unreachable("Invalid relocation type" ); |
154 | } |
155 | } |
156 | |
157 | static bool supportsMSP430(uint64_t Type) { |
158 | switch (Type) { |
159 | case ELF::R_MSP430_32: |
160 | case ELF::R_MSP430_16_BYTE: |
161 | return true; |
162 | default: |
163 | return false; |
164 | } |
165 | } |
166 | |
167 | static uint64_t resolveMSP430(uint64_t Type, uint64_t Offset, uint64_t S, |
168 | uint64_t /*LocData*/, int64_t Addend) { |
169 | switch (Type) { |
170 | case ELF::R_MSP430_32: |
171 | return (S + Addend) & 0xFFFFFFFF; |
172 | case ELF::R_MSP430_16_BYTE: |
173 | return (S + Addend) & 0xFFFF; |
174 | default: |
175 | llvm_unreachable("Invalid relocation type" ); |
176 | } |
177 | } |
178 | |
179 | static bool supportsPPC64(uint64_t Type) { |
180 | switch (Type) { |
181 | case ELF::R_PPC64_ADDR32: |
182 | case ELF::R_PPC64_ADDR64: |
183 | case ELF::R_PPC64_REL32: |
184 | case ELF::R_PPC64_REL64: |
185 | return true; |
186 | default: |
187 | return false; |
188 | } |
189 | } |
190 | |
191 | static uint64_t resolvePPC64(uint64_t Type, uint64_t Offset, uint64_t S, |
192 | uint64_t /*LocData*/, int64_t Addend) { |
193 | switch (Type) { |
194 | case ELF::R_PPC64_ADDR32: |
195 | return (S + Addend) & 0xFFFFFFFF; |
196 | case ELF::R_PPC64_ADDR64: |
197 | return S + Addend; |
198 | case ELF::R_PPC64_REL32: |
199 | return (S + Addend - Offset) & 0xFFFFFFFF; |
200 | case ELF::R_PPC64_REL64: |
201 | return S + Addend - Offset; |
202 | default: |
203 | llvm_unreachable("Invalid relocation type" ); |
204 | } |
205 | } |
206 | |
207 | static bool supportsSystemZ(uint64_t Type) { |
208 | switch (Type) { |
209 | case ELF::R_390_32: |
210 | case ELF::R_390_64: |
211 | return true; |
212 | default: |
213 | return false; |
214 | } |
215 | } |
216 | |
217 | static uint64_t resolveSystemZ(uint64_t Type, uint64_t Offset, uint64_t S, |
218 | uint64_t /*LocData*/, int64_t Addend) { |
219 | switch (Type) { |
220 | case ELF::R_390_32: |
221 | return (S + Addend) & 0xFFFFFFFF; |
222 | case ELF::R_390_64: |
223 | return S + Addend; |
224 | default: |
225 | llvm_unreachable("Invalid relocation type" ); |
226 | } |
227 | } |
228 | |
229 | static bool supportsSparc64(uint64_t Type) { |
230 | switch (Type) { |
231 | case ELF::R_SPARC_32: |
232 | case ELF::R_SPARC_64: |
233 | case ELF::R_SPARC_UA32: |
234 | case ELF::R_SPARC_UA64: |
235 | return true; |
236 | default: |
237 | return false; |
238 | } |
239 | } |
240 | |
241 | static uint64_t resolveSparc64(uint64_t Type, uint64_t Offset, uint64_t S, |
242 | uint64_t /*LocData*/, int64_t Addend) { |
243 | switch (Type) { |
244 | case ELF::R_SPARC_32: |
245 | case ELF::R_SPARC_64: |
246 | case ELF::R_SPARC_UA32: |
247 | case ELF::R_SPARC_UA64: |
248 | return S + Addend; |
249 | default: |
250 | llvm_unreachable("Invalid relocation type" ); |
251 | } |
252 | } |
253 | |
254 | /// Returns true if \c Obj is an AMDGPU code object based solely on the value |
255 | /// of e_machine. |
256 | /// |
257 | /// AMDGPU code objects with an e_machine of EF_AMDGPU_MACH_NONE do not |
258 | /// identify their arch as either r600 or amdgcn, but we can still handle |
259 | /// their relocations. When we identify an ELF object with an UnknownArch, |
260 | /// we use isAMDGPU to check for this case. |
261 | static bool isAMDGPU(const ObjectFile &Obj) { |
262 | if (const auto *ELFObj = dyn_cast<ELFObjectFileBase>(Val: &Obj)) |
263 | return ELFObj->getEMachine() == ELF::EM_AMDGPU; |
264 | return false; |
265 | } |
266 | |
267 | static bool supportsAmdgpu(uint64_t Type) { |
268 | switch (Type) { |
269 | case ELF::R_AMDGPU_ABS32: |
270 | case ELF::R_AMDGPU_ABS64: |
271 | return true; |
272 | default: |
273 | return false; |
274 | } |
275 | } |
276 | |
277 | static uint64_t resolveAmdgpu(uint64_t Type, uint64_t Offset, uint64_t S, |
278 | uint64_t /*LocData*/, int64_t Addend) { |
279 | switch (Type) { |
280 | case ELF::R_AMDGPU_ABS32: |
281 | case ELF::R_AMDGPU_ABS64: |
282 | return S + Addend; |
283 | default: |
284 | llvm_unreachable("Invalid relocation type" ); |
285 | } |
286 | } |
287 | |
288 | static bool supportsX86(uint64_t Type) { |
289 | switch (Type) { |
290 | case ELF::R_386_NONE: |
291 | case ELF::R_386_32: |
292 | case ELF::R_386_PC32: |
293 | return true; |
294 | default: |
295 | return false; |
296 | } |
297 | } |
298 | |
299 | static uint64_t resolveX86(uint64_t Type, uint64_t Offset, uint64_t S, |
300 | uint64_t LocData, int64_t /*Addend*/) { |
301 | switch (Type) { |
302 | case ELF::R_386_NONE: |
303 | return LocData; |
304 | case ELF::R_386_32: |
305 | return S + LocData; |
306 | case ELF::R_386_PC32: |
307 | return S - Offset + LocData; |
308 | default: |
309 | llvm_unreachable("Invalid relocation type" ); |
310 | } |
311 | } |
312 | |
313 | static bool supportsPPC32(uint64_t Type) { |
314 | switch (Type) { |
315 | case ELF::R_PPC_ADDR32: |
316 | case ELF::R_PPC_REL32: |
317 | return true; |
318 | default: |
319 | return false; |
320 | } |
321 | } |
322 | |
323 | static uint64_t resolvePPC32(uint64_t Type, uint64_t Offset, uint64_t S, |
324 | uint64_t /*LocData*/, int64_t Addend) { |
325 | switch (Type) { |
326 | case ELF::R_PPC_ADDR32: |
327 | return (S + Addend) & 0xFFFFFFFF; |
328 | case ELF::R_PPC_REL32: |
329 | return (S + Addend - Offset) & 0xFFFFFFFF; |
330 | } |
331 | llvm_unreachable("Invalid relocation type" ); |
332 | } |
333 | |
334 | static bool supportsARM(uint64_t Type) { |
335 | switch (Type) { |
336 | case ELF::R_ARM_ABS32: |
337 | case ELF::R_ARM_REL32: |
338 | return true; |
339 | default: |
340 | return false; |
341 | } |
342 | } |
343 | |
344 | static uint64_t resolveARM(uint64_t Type, uint64_t Offset, uint64_t S, |
345 | uint64_t LocData, int64_t Addend) { |
346 | // Support both RELA and REL relocations. The caller is responsible |
347 | // for supplying the correct values for LocData and Addend, i.e. |
348 | // Addend == 0 for REL and LocData == 0 for RELA. |
349 | assert((LocData == 0 || Addend == 0) && |
350 | "one of LocData and Addend must be 0" ); |
351 | switch (Type) { |
352 | case ELF::R_ARM_ABS32: |
353 | return (S + LocData + Addend) & 0xFFFFFFFF; |
354 | case ELF::R_ARM_REL32: |
355 | return (S + LocData + Addend - Offset) & 0xFFFFFFFF; |
356 | } |
357 | llvm_unreachable("Invalid relocation type" ); |
358 | } |
359 | |
360 | static bool supportsAVR(uint64_t Type) { |
361 | switch (Type) { |
362 | case ELF::R_AVR_16: |
363 | case ELF::R_AVR_32: |
364 | return true; |
365 | default: |
366 | return false; |
367 | } |
368 | } |
369 | |
370 | static uint64_t resolveAVR(uint64_t Type, uint64_t Offset, uint64_t S, |
371 | uint64_t /*LocData*/, int64_t Addend) { |
372 | switch (Type) { |
373 | case ELF::R_AVR_16: |
374 | return (S + Addend) & 0xFFFF; |
375 | case ELF::R_AVR_32: |
376 | return (S + Addend) & 0xFFFFFFFF; |
377 | default: |
378 | llvm_unreachable("Invalid relocation type" ); |
379 | } |
380 | } |
381 | |
382 | static bool supportsLanai(uint64_t Type) { |
383 | return Type == ELF::R_LANAI_32; |
384 | } |
385 | |
386 | static uint64_t resolveLanai(uint64_t Type, uint64_t Offset, uint64_t S, |
387 | uint64_t /*LocData*/, int64_t Addend) { |
388 | if (Type == ELF::R_LANAI_32) |
389 | return (S + Addend) & 0xFFFFFFFF; |
390 | llvm_unreachable("Invalid relocation type" ); |
391 | } |
392 | |
393 | static bool supportsMips32(uint64_t Type) { |
394 | switch (Type) { |
395 | case ELF::R_MIPS_32: |
396 | case ELF::R_MIPS_TLS_DTPREL32: |
397 | return true; |
398 | default: |
399 | return false; |
400 | } |
401 | } |
402 | |
403 | static uint64_t resolveMips32(uint64_t Type, uint64_t Offset, uint64_t S, |
404 | uint64_t LocData, int64_t /*Addend*/) { |
405 | // FIXME: Take in account implicit addends to get correct results. |
406 | if (Type == ELF::R_MIPS_32) |
407 | return (S + LocData) & 0xFFFFFFFF; |
408 | if (Type == ELF::R_MIPS_TLS_DTPREL32) |
409 | return (S + LocData) & 0xFFFFFFFF; |
410 | llvm_unreachable("Invalid relocation type" ); |
411 | } |
412 | |
413 | static bool supportsSparc32(uint64_t Type) { |
414 | switch (Type) { |
415 | case ELF::R_SPARC_32: |
416 | case ELF::R_SPARC_UA32: |
417 | return true; |
418 | default: |
419 | return false; |
420 | } |
421 | } |
422 | |
423 | static uint64_t resolveSparc32(uint64_t Type, uint64_t Offset, uint64_t S, |
424 | uint64_t LocData, int64_t Addend) { |
425 | if (Type == ELF::R_SPARC_32 || Type == ELF::R_SPARC_UA32) |
426 | return S + Addend; |
427 | return LocData; |
428 | } |
429 | |
430 | static bool supportsHexagon(uint64_t Type) { |
431 | return Type == ELF::R_HEX_32; |
432 | } |
433 | |
434 | static uint64_t resolveHexagon(uint64_t Type, uint64_t Offset, uint64_t S, |
435 | uint64_t /*LocData*/, int64_t Addend) { |
436 | if (Type == ELF::R_HEX_32) |
437 | return S + Addend; |
438 | llvm_unreachable("Invalid relocation type" ); |
439 | } |
440 | |
441 | static bool supportsRISCV(uint64_t Type) { |
442 | switch (Type) { |
443 | case ELF::R_RISCV_NONE: |
444 | case ELF::R_RISCV_32: |
445 | case ELF::R_RISCV_32_PCREL: |
446 | case ELF::R_RISCV_64: |
447 | case ELF::R_RISCV_SET6: |
448 | case ELF::R_RISCV_SET8: |
449 | case ELF::R_RISCV_SUB6: |
450 | case ELF::R_RISCV_ADD8: |
451 | case ELF::R_RISCV_SUB8: |
452 | case ELF::R_RISCV_SET16: |
453 | case ELF::R_RISCV_ADD16: |
454 | case ELF::R_RISCV_SUB16: |
455 | case ELF::R_RISCV_SET32: |
456 | case ELF::R_RISCV_ADD32: |
457 | case ELF::R_RISCV_SUB32: |
458 | case ELF::R_RISCV_ADD64: |
459 | case ELF::R_RISCV_SUB64: |
460 | return true; |
461 | default: |
462 | return false; |
463 | } |
464 | } |
465 | |
466 | static uint64_t resolveRISCV(uint64_t Type, uint64_t Offset, uint64_t S, |
467 | uint64_t LocData, int64_t Addend) { |
468 | int64_t RA = Addend; |
469 | uint64_t A = LocData; |
470 | switch (Type) { |
471 | case ELF::R_RISCV_NONE: |
472 | return LocData; |
473 | case ELF::R_RISCV_32: |
474 | return (S + RA) & 0xFFFFFFFF; |
475 | case ELF::R_RISCV_32_PCREL: |
476 | return (S + RA - Offset) & 0xFFFFFFFF; |
477 | case ELF::R_RISCV_64: |
478 | return S + RA; |
479 | case ELF::R_RISCV_SET6: |
480 | return (A & 0xC0) | ((S + RA) & 0x3F); |
481 | case ELF::R_RISCV_SUB6: |
482 | return (A & 0xC0) | (((A & 0x3F) - (S + RA)) & 0x3F); |
483 | case ELF::R_RISCV_SET8: |
484 | return (S + RA) & 0xFF; |
485 | case ELF::R_RISCV_ADD8: |
486 | return (A + (S + RA)) & 0xFF; |
487 | case ELF::R_RISCV_SUB8: |
488 | return (A - (S + RA)) & 0xFF; |
489 | case ELF::R_RISCV_SET16: |
490 | return (S + RA) & 0xFFFF; |
491 | case ELF::R_RISCV_ADD16: |
492 | return (A + (S + RA)) & 0xFFFF; |
493 | case ELF::R_RISCV_SUB16: |
494 | return (A - (S + RA)) & 0xFFFF; |
495 | case ELF::R_RISCV_SET32: |
496 | return (S + RA) & 0xFFFFFFFF; |
497 | case ELF::R_RISCV_ADD32: |
498 | return (A + (S + RA)) & 0xFFFFFFFF; |
499 | case ELF::R_RISCV_SUB32: |
500 | return (A - (S + RA)) & 0xFFFFFFFF; |
501 | case ELF::R_RISCV_ADD64: |
502 | return (A + (S + RA)); |
503 | case ELF::R_RISCV_SUB64: |
504 | return (A - (S + RA)); |
505 | default: |
506 | llvm_unreachable("Invalid relocation type" ); |
507 | } |
508 | } |
509 | |
510 | static bool supportsCSKY(uint64_t Type) { |
511 | switch (Type) { |
512 | case ELF::R_CKCORE_NONE: |
513 | case ELF::R_CKCORE_ADDR32: |
514 | case ELF::R_CKCORE_PCREL32: |
515 | return true; |
516 | default: |
517 | return false; |
518 | } |
519 | } |
520 | |
521 | static uint64_t resolveCSKY(uint64_t Type, uint64_t Offset, uint64_t S, |
522 | uint64_t LocData, int64_t Addend) { |
523 | switch (Type) { |
524 | case ELF::R_CKCORE_NONE: |
525 | return LocData; |
526 | case ELF::R_CKCORE_ADDR32: |
527 | return (S + Addend) & 0xFFFFFFFF; |
528 | case ELF::R_CKCORE_PCREL32: |
529 | return (S + Addend - Offset) & 0xFFFFFFFF; |
530 | default: |
531 | llvm_unreachable("Invalid relocation type" ); |
532 | } |
533 | } |
534 | |
535 | static bool supportsLoongArch(uint64_t Type) { |
536 | switch (Type) { |
537 | case ELF::R_LARCH_NONE: |
538 | case ELF::R_LARCH_32: |
539 | case ELF::R_LARCH_32_PCREL: |
540 | case ELF::R_LARCH_64: |
541 | case ELF::R_LARCH_ADD6: |
542 | case ELF::R_LARCH_SUB6: |
543 | case ELF::R_LARCH_ADD8: |
544 | case ELF::R_LARCH_SUB8: |
545 | case ELF::R_LARCH_ADD16: |
546 | case ELF::R_LARCH_SUB16: |
547 | case ELF::R_LARCH_ADD32: |
548 | case ELF::R_LARCH_SUB32: |
549 | case ELF::R_LARCH_ADD64: |
550 | case ELF::R_LARCH_SUB64: |
551 | return true; |
552 | default: |
553 | return false; |
554 | } |
555 | } |
556 | |
557 | static uint64_t resolveLoongArch(uint64_t Type, uint64_t Offset, uint64_t S, |
558 | uint64_t LocData, int64_t Addend) { |
559 | switch (Type) { |
560 | case ELF::R_LARCH_NONE: |
561 | return LocData; |
562 | case ELF::R_LARCH_32: |
563 | return (S + Addend) & 0xFFFFFFFF; |
564 | case ELF::R_LARCH_32_PCREL: |
565 | return (S + Addend - Offset) & 0xFFFFFFFF; |
566 | case ELF::R_LARCH_64: |
567 | return S + Addend; |
568 | case ELF::R_LARCH_ADD6: |
569 | return (LocData & 0xC0) | ((LocData + S + Addend) & 0x3F); |
570 | case ELF::R_LARCH_SUB6: |
571 | return (LocData & 0xC0) | ((LocData - (S + Addend)) & 0x3F); |
572 | case ELF::R_LARCH_ADD8: |
573 | return (LocData + (S + Addend)) & 0xFF; |
574 | case ELF::R_LARCH_SUB8: |
575 | return (LocData - (S + Addend)) & 0xFF; |
576 | case ELF::R_LARCH_ADD16: |
577 | return (LocData + (S + Addend)) & 0xFFFF; |
578 | case ELF::R_LARCH_SUB16: |
579 | return (LocData - (S + Addend)) & 0xFFFF; |
580 | case ELF::R_LARCH_ADD32: |
581 | return (LocData + (S + Addend)) & 0xFFFFFFFF; |
582 | case ELF::R_LARCH_SUB32: |
583 | return (LocData - (S + Addend)) & 0xFFFFFFFF; |
584 | case ELF::R_LARCH_ADD64: |
585 | return (LocData + (S + Addend)); |
586 | case ELF::R_LARCH_SUB64: |
587 | return (LocData - (S + Addend)); |
588 | default: |
589 | llvm_unreachable("Invalid relocation type" ); |
590 | } |
591 | } |
592 | |
593 | static bool supportsCOFFX86(uint64_t Type) { |
594 | switch (Type) { |
595 | case COFF::IMAGE_REL_I386_SECREL: |
596 | case COFF::IMAGE_REL_I386_DIR32: |
597 | return true; |
598 | default: |
599 | return false; |
600 | } |
601 | } |
602 | |
603 | static uint64_t resolveCOFFX86(uint64_t Type, uint64_t Offset, uint64_t S, |
604 | uint64_t LocData, int64_t /*Addend*/) { |
605 | switch (Type) { |
606 | case COFF::IMAGE_REL_I386_SECREL: |
607 | case COFF::IMAGE_REL_I386_DIR32: |
608 | return (S + LocData) & 0xFFFFFFFF; |
609 | default: |
610 | llvm_unreachable("Invalid relocation type" ); |
611 | } |
612 | } |
613 | |
614 | static bool supportsCOFFX86_64(uint64_t Type) { |
615 | switch (Type) { |
616 | case COFF::IMAGE_REL_AMD64_SECREL: |
617 | case COFF::IMAGE_REL_AMD64_ADDR64: |
618 | return true; |
619 | default: |
620 | return false; |
621 | } |
622 | } |
623 | |
624 | static uint64_t resolveCOFFX86_64(uint64_t Type, uint64_t Offset, uint64_t S, |
625 | uint64_t LocData, int64_t /*Addend*/) { |
626 | switch (Type) { |
627 | case COFF::IMAGE_REL_AMD64_SECREL: |
628 | return (S + LocData) & 0xFFFFFFFF; |
629 | case COFF::IMAGE_REL_AMD64_ADDR64: |
630 | return S + LocData; |
631 | default: |
632 | llvm_unreachable("Invalid relocation type" ); |
633 | } |
634 | } |
635 | |
636 | static bool supportsCOFFARM(uint64_t Type) { |
637 | switch (Type) { |
638 | case COFF::IMAGE_REL_ARM_SECREL: |
639 | case COFF::IMAGE_REL_ARM_ADDR32: |
640 | return true; |
641 | default: |
642 | return false; |
643 | } |
644 | } |
645 | |
646 | static uint64_t resolveCOFFARM(uint64_t Type, uint64_t Offset, uint64_t S, |
647 | uint64_t LocData, int64_t /*Addend*/) { |
648 | switch (Type) { |
649 | case COFF::IMAGE_REL_ARM_SECREL: |
650 | case COFF::IMAGE_REL_ARM_ADDR32: |
651 | return (S + LocData) & 0xFFFFFFFF; |
652 | default: |
653 | llvm_unreachable("Invalid relocation type" ); |
654 | } |
655 | } |
656 | |
657 | static bool supportsCOFFARM64(uint64_t Type) { |
658 | switch (Type) { |
659 | case COFF::IMAGE_REL_ARM64_SECREL: |
660 | case COFF::IMAGE_REL_ARM64_ADDR64: |
661 | return true; |
662 | default: |
663 | return false; |
664 | } |
665 | } |
666 | |
667 | static uint64_t resolveCOFFARM64(uint64_t Type, uint64_t Offset, uint64_t S, |
668 | uint64_t LocData, int64_t /*Addend*/) { |
669 | switch (Type) { |
670 | case COFF::IMAGE_REL_ARM64_SECREL: |
671 | return (S + LocData) & 0xFFFFFFFF; |
672 | case COFF::IMAGE_REL_ARM64_ADDR64: |
673 | return S + LocData; |
674 | default: |
675 | llvm_unreachable("Invalid relocation type" ); |
676 | } |
677 | } |
678 | |
679 | static bool supportsMachOX86_64(uint64_t Type) { |
680 | return Type == MachO::X86_64_RELOC_UNSIGNED; |
681 | } |
682 | |
683 | static uint64_t resolveMachOX86_64(uint64_t Type, uint64_t Offset, uint64_t S, |
684 | uint64_t LocData, int64_t /*Addend*/) { |
685 | if (Type == MachO::X86_64_RELOC_UNSIGNED) |
686 | return S; |
687 | llvm_unreachable("Invalid relocation type" ); |
688 | } |
689 | |
690 | static bool supportsWasm32(uint64_t Type) { |
691 | switch (Type) { |
692 | case wasm::R_WASM_FUNCTION_INDEX_LEB: |
693 | case wasm::R_WASM_TABLE_INDEX_SLEB: |
694 | case wasm::R_WASM_TABLE_INDEX_I32: |
695 | case wasm::R_WASM_MEMORY_ADDR_LEB: |
696 | case wasm::R_WASM_MEMORY_ADDR_SLEB: |
697 | case wasm::R_WASM_MEMORY_ADDR_I32: |
698 | case wasm::R_WASM_TYPE_INDEX_LEB: |
699 | case wasm::R_WASM_GLOBAL_INDEX_LEB: |
700 | case wasm::R_WASM_FUNCTION_OFFSET_I32: |
701 | case wasm::R_WASM_SECTION_OFFSET_I32: |
702 | case wasm::R_WASM_TAG_INDEX_LEB: |
703 | case wasm::R_WASM_GLOBAL_INDEX_I32: |
704 | case wasm::R_WASM_TABLE_NUMBER_LEB: |
705 | case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32: |
706 | return true; |
707 | default: |
708 | return false; |
709 | } |
710 | } |
711 | |
712 | static bool supportsWasm64(uint64_t Type) { |
713 | switch (Type) { |
714 | case wasm::R_WASM_MEMORY_ADDR_LEB64: |
715 | case wasm::R_WASM_MEMORY_ADDR_SLEB64: |
716 | case wasm::R_WASM_MEMORY_ADDR_I64: |
717 | case wasm::R_WASM_TABLE_INDEX_SLEB64: |
718 | case wasm::R_WASM_TABLE_INDEX_I64: |
719 | case wasm::R_WASM_FUNCTION_OFFSET_I64: |
720 | return true; |
721 | default: |
722 | return supportsWasm32(Type); |
723 | } |
724 | } |
725 | |
726 | static uint64_t resolveWasm32(uint64_t Type, uint64_t Offset, uint64_t S, |
727 | uint64_t LocData, int64_t /*Addend*/) { |
728 | switch (Type) { |
729 | case wasm::R_WASM_FUNCTION_INDEX_LEB: |
730 | case wasm::R_WASM_TABLE_INDEX_SLEB: |
731 | case wasm::R_WASM_TABLE_INDEX_I32: |
732 | case wasm::R_WASM_MEMORY_ADDR_LEB: |
733 | case wasm::R_WASM_MEMORY_ADDR_SLEB: |
734 | case wasm::R_WASM_MEMORY_ADDR_I32: |
735 | case wasm::R_WASM_TYPE_INDEX_LEB: |
736 | case wasm::R_WASM_GLOBAL_INDEX_LEB: |
737 | case wasm::R_WASM_FUNCTION_OFFSET_I32: |
738 | case wasm::R_WASM_SECTION_OFFSET_I32: |
739 | case wasm::R_WASM_TAG_INDEX_LEB: |
740 | case wasm::R_WASM_GLOBAL_INDEX_I32: |
741 | case wasm::R_WASM_TABLE_NUMBER_LEB: |
742 | case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32: |
743 | // For wasm section, its offset at 0 -- ignoring Value |
744 | return LocData; |
745 | default: |
746 | llvm_unreachable("Invalid relocation type" ); |
747 | } |
748 | } |
749 | |
750 | static uint64_t resolveWasm64(uint64_t Type, uint64_t Offset, uint64_t S, |
751 | uint64_t LocData, int64_t Addend) { |
752 | switch (Type) { |
753 | case wasm::R_WASM_MEMORY_ADDR_LEB64: |
754 | case wasm::R_WASM_MEMORY_ADDR_SLEB64: |
755 | case wasm::R_WASM_MEMORY_ADDR_I64: |
756 | case wasm::R_WASM_TABLE_INDEX_SLEB64: |
757 | case wasm::R_WASM_TABLE_INDEX_I64: |
758 | case wasm::R_WASM_FUNCTION_OFFSET_I64: |
759 | // For wasm section, its offset at 0 -- ignoring Value |
760 | return LocData; |
761 | default: |
762 | return resolveWasm32(Type, Offset, S, LocData, Addend); |
763 | } |
764 | } |
765 | |
766 | std::pair<SupportsRelocation, RelocationResolver> |
767 | getRelocationResolver(const ObjectFile &Obj) { |
768 | if (Obj.isCOFF()) { |
769 | switch (Obj.getArch()) { |
770 | case Triple::x86_64: |
771 | return {supportsCOFFX86_64, resolveCOFFX86_64}; |
772 | case Triple::x86: |
773 | return {supportsCOFFX86, resolveCOFFX86}; |
774 | case Triple::arm: |
775 | case Triple::thumb: |
776 | return {supportsCOFFARM, resolveCOFFARM}; |
777 | case Triple::aarch64: |
778 | return {supportsCOFFARM64, resolveCOFFARM64}; |
779 | default: |
780 | return {nullptr, nullptr}; |
781 | } |
782 | } else if (Obj.isELF()) { |
783 | if (Obj.getBytesInAddress() == 8) { |
784 | switch (Obj.getArch()) { |
785 | case Triple::x86_64: |
786 | return {supportsX86_64, resolveX86_64}; |
787 | case Triple::aarch64: |
788 | case Triple::aarch64_be: |
789 | return {supportsAArch64, resolveAArch64}; |
790 | case Triple::bpfel: |
791 | case Triple::bpfeb: |
792 | return {supportsBPF, resolveBPF}; |
793 | case Triple::loongarch64: |
794 | return {supportsLoongArch, resolveLoongArch}; |
795 | case Triple::mips64el: |
796 | case Triple::mips64: |
797 | return {supportsMips64, resolveMips64}; |
798 | case Triple::ppc64le: |
799 | case Triple::ppc64: |
800 | return {supportsPPC64, resolvePPC64}; |
801 | case Triple::systemz: |
802 | return {supportsSystemZ, resolveSystemZ}; |
803 | case Triple::sparcv9: |
804 | return {supportsSparc64, resolveSparc64}; |
805 | case Triple::amdgcn: |
806 | return {supportsAmdgpu, resolveAmdgpu}; |
807 | case Triple::riscv64: |
808 | return {supportsRISCV, resolveRISCV}; |
809 | default: |
810 | if (isAMDGPU(Obj)) |
811 | return {supportsAmdgpu, resolveAmdgpu}; |
812 | return {nullptr, nullptr}; |
813 | } |
814 | } |
815 | |
816 | // 32-bit object file |
817 | assert(Obj.getBytesInAddress() == 4 && |
818 | "Invalid word size in object file" ); |
819 | |
820 | switch (Obj.getArch()) { |
821 | case Triple::x86: |
822 | return {supportsX86, resolveX86}; |
823 | case Triple::ppcle: |
824 | case Triple::ppc: |
825 | return {supportsPPC32, resolvePPC32}; |
826 | case Triple::arm: |
827 | case Triple::armeb: |
828 | return {supportsARM, resolveARM}; |
829 | case Triple::avr: |
830 | return {supportsAVR, resolveAVR}; |
831 | case Triple::lanai: |
832 | return {supportsLanai, resolveLanai}; |
833 | case Triple::loongarch32: |
834 | return {supportsLoongArch, resolveLoongArch}; |
835 | case Triple::mipsel: |
836 | case Triple::mips: |
837 | return {supportsMips32, resolveMips32}; |
838 | case Triple::msp430: |
839 | return {supportsMSP430, resolveMSP430}; |
840 | case Triple::sparc: |
841 | return {supportsSparc32, resolveSparc32}; |
842 | case Triple::hexagon: |
843 | return {supportsHexagon, resolveHexagon}; |
844 | case Triple::r600: |
845 | return {supportsAmdgpu, resolveAmdgpu}; |
846 | case Triple::riscv32: |
847 | return {supportsRISCV, resolveRISCV}; |
848 | case Triple::csky: |
849 | return {supportsCSKY, resolveCSKY}; |
850 | default: |
851 | if (isAMDGPU(Obj)) |
852 | return {supportsAmdgpu, resolveAmdgpu}; |
853 | return {nullptr, nullptr}; |
854 | } |
855 | } else if (Obj.isMachO()) { |
856 | if (Obj.getArch() == Triple::x86_64) |
857 | return {supportsMachOX86_64, resolveMachOX86_64}; |
858 | return {nullptr, nullptr}; |
859 | } else if (Obj.isWasm()) { |
860 | if (Obj.getArch() == Triple::wasm32) |
861 | return {supportsWasm32, resolveWasm32}; |
862 | if (Obj.getArch() == Triple::wasm64) |
863 | return {supportsWasm64, resolveWasm64}; |
864 | return {nullptr, nullptr}; |
865 | } |
866 | |
867 | llvm_unreachable("Invalid object file" ); |
868 | } |
869 | |
870 | uint64_t resolveRelocation(RelocationResolver Resolver, const RelocationRef &R, |
871 | uint64_t S, uint64_t LocData) { |
872 | if (const ObjectFile *Obj = R.getObject()) { |
873 | int64_t Addend = 0; |
874 | if (Obj->isELF()) { |
875 | auto GetRelSectionType = [&]() -> unsigned { |
876 | if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(Val: Obj)) |
877 | return Elf32LEObj->getRelSection(Rel: R.getRawDataRefImpl())->sh_type; |
878 | if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(Val: Obj)) |
879 | return Elf64LEObj->getRelSection(Rel: R.getRawDataRefImpl())->sh_type; |
880 | if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(Val: Obj)) |
881 | return Elf32BEObj->getRelSection(Rel: R.getRawDataRefImpl())->sh_type; |
882 | auto *Elf64BEObj = cast<ELF64BEObjectFile>(Val: Obj); |
883 | return Elf64BEObj->getRelSection(Rel: R.getRawDataRefImpl())->sh_type; |
884 | }; |
885 | |
886 | if (GetRelSectionType() == ELF::SHT_RELA) { |
887 | Addend = getELFAddend(R); |
888 | // LoongArch and RISCV relocations use both LocData and Addend. |
889 | if (Obj->getArch() != Triple::loongarch32 && |
890 | Obj->getArch() != Triple::loongarch64 && |
891 | Obj->getArch() != Triple::riscv32 && |
892 | Obj->getArch() != Triple::riscv64) |
893 | LocData = 0; |
894 | } |
895 | } |
896 | |
897 | return Resolver(R.getType(), R.getOffset(), S, LocData, Addend); |
898 | } |
899 | |
900 | // Sometimes the caller might want to use its own specific implementation of |
901 | // the resolver function. E.g. this is used by LLD when it resolves debug |
902 | // relocations and assumes that all of them have the same computation (S + A). |
903 | // The relocation R has no owner object in this case and we don't need to |
904 | // provide Type and Offset fields. It is also assumed the DataRefImpl.p |
905 | // contains the addend, provided by the caller. |
906 | return Resolver(/*Type=*/0, /*Offset=*/0, S, LocData, |
907 | R.getRawDataRefImpl().p); |
908 | } |
909 | |
910 | } // namespace object |
911 | } // namespace llvm |
912 | |