xref: /freebsd/contrib/llvm-project/llvm/lib/Object/RelocationResolver.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
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(AddendOrErr.takeError(), [](const ErrorInfoBase &EI) {
35     report_fatal_error(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>(&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>(Obj))
877           return Elf32LEObj->getRelSection(R.getRawDataRefImpl())->sh_type;
878         if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(Obj))
879           return Elf64LEObj->getRelSection(R.getRawDataRefImpl())->sh_type;
880         if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(Obj))
881           return Elf32BEObj->getRelSection(R.getRawDataRefImpl())->sh_type;
882         auto *Elf64BEObj = cast<ELF64BEObjectFile>(Obj);
883         return Elf64BEObj->getRelSection(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