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