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