xref: /llvm-project/llvm/lib/Object/RelocationResolver.cpp (revision e9c8106a90d49e75bac87341ade57c6049357a97)
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(AddendOrErr.takeError(), [](const ErrorInfoBase &EI) {
34     report_fatal_error(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>(&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   switch (Type) {
279   case ELF::R_AMDGPU_ABS32:
280   case ELF::R_AMDGPU_ABS64:
281     return S + Addend;
282   default:
283     llvm_unreachable("Invalid relocation type");
284   }
285 }
286 
287 static bool supportsX86(uint64_t Type) {
288   switch (Type) {
289   case ELF::R_386_NONE:
290   case ELF::R_386_32:
291   case ELF::R_386_PC32:
292     return true;
293   default:
294     return false;
295   }
296 }
297 
298 static uint64_t resolveX86(uint64_t Type, uint64_t Offset, uint64_t S,
299                            uint64_t LocData, int64_t /*Addend*/) {
300   switch (Type) {
301   case ELF::R_386_NONE:
302     return LocData;
303   case ELF::R_386_32:
304     return S + LocData;
305   case ELF::R_386_PC32:
306     return S - Offset + LocData;
307   default:
308     llvm_unreachable("Invalid relocation type");
309   }
310 }
311 
312 static bool supportsPPC32(uint64_t Type) {
313   switch (Type) {
314   case ELF::R_PPC_ADDR32:
315   case ELF::R_PPC_REL32:
316     return true;
317   default:
318     return false;
319   }
320 }
321 
322 static uint64_t resolvePPC32(uint64_t Type, uint64_t Offset, uint64_t S,
323                              uint64_t /*LocData*/, int64_t Addend) {
324   switch (Type) {
325   case ELF::R_PPC_ADDR32:
326     return (S + Addend) & 0xFFFFFFFF;
327   case ELF::R_PPC_REL32:
328     return (S + Addend - Offset) & 0xFFFFFFFF;
329   }
330   llvm_unreachable("Invalid relocation type");
331 }
332 
333 static bool supportsARM(uint64_t Type) {
334   switch (Type) {
335   case ELF::R_ARM_ABS32:
336   case ELF::R_ARM_REL32:
337     return true;
338   default:
339     return false;
340   }
341 }
342 
343 static uint64_t resolveARM(uint64_t Type, uint64_t Offset, uint64_t S,
344                            uint64_t LocData, int64_t Addend) {
345   // Support both RELA and REL relocations. The caller is responsible
346   // for supplying the correct values for LocData and Addend, i.e.
347   // Addend == 0 for REL and LocData == 0 for RELA.
348   assert((LocData == 0 || Addend == 0) &&
349          "one of LocData and Addend must be 0");
350   switch (Type) {
351   case ELF::R_ARM_ABS32:
352     return (S + LocData + Addend) & 0xFFFFFFFF;
353   case ELF::R_ARM_REL32:
354     return (S + LocData + Addend - Offset) & 0xFFFFFFFF;
355   }
356   llvm_unreachable("Invalid relocation type");
357 }
358 
359 static bool supportsAVR(uint64_t Type) {
360   switch (Type) {
361   case ELF::R_AVR_16:
362   case ELF::R_AVR_32:
363     return true;
364   default:
365     return false;
366   }
367 }
368 
369 static uint64_t resolveAVR(uint64_t Type, uint64_t Offset, uint64_t S,
370                            uint64_t /*LocData*/, int64_t Addend) {
371   switch (Type) {
372   case ELF::R_AVR_16:
373     return (S + Addend) & 0xFFFF;
374   case ELF::R_AVR_32:
375     return (S + Addend) & 0xFFFFFFFF;
376   default:
377     llvm_unreachable("Invalid relocation type");
378   }
379 }
380 
381 static bool supportsLanai(uint64_t Type) {
382   return Type == ELF::R_LANAI_32;
383 }
384 
385 static uint64_t resolveLanai(uint64_t Type, uint64_t Offset, uint64_t S,
386                              uint64_t /*LocData*/, int64_t Addend) {
387   if (Type == ELF::R_LANAI_32)
388     return (S + Addend) & 0xFFFFFFFF;
389   llvm_unreachable("Invalid relocation type");
390 }
391 
392 static bool supportsMips32(uint64_t Type) {
393   switch (Type) {
394   case ELF::R_MIPS_32:
395   case ELF::R_MIPS_TLS_DTPREL32:
396     return true;
397   default:
398     return false;
399   }
400 }
401 
402 static uint64_t resolveMips32(uint64_t Type, uint64_t Offset, uint64_t S,
403                               uint64_t LocData, int64_t /*Addend*/) {
404   // FIXME: Take in account implicit addends to get correct results.
405   if (Type == ELF::R_MIPS_32)
406     return (S + LocData) & 0xFFFFFFFF;
407   if (Type == ELF::R_MIPS_TLS_DTPREL32)
408     return (S + LocData) & 0xFFFFFFFF;
409   llvm_unreachable("Invalid relocation type");
410 }
411 
412 static bool supportsSparc32(uint64_t Type) {
413   switch (Type) {
414   case ELF::R_SPARC_32:
415   case ELF::R_SPARC_UA32:
416     return true;
417   default:
418     return false;
419   }
420 }
421 
422 static uint64_t resolveSparc32(uint64_t Type, uint64_t Offset, uint64_t S,
423                                uint64_t LocData, int64_t Addend) {
424   if (Type == ELF::R_SPARC_32 || Type == ELF::R_SPARC_UA32)
425     return S + Addend;
426   return LocData;
427 }
428 
429 static bool supportsHexagon(uint64_t Type) {
430   return Type == ELF::R_HEX_32;
431 }
432 
433 static uint64_t resolveHexagon(uint64_t Type, uint64_t Offset, uint64_t S,
434                                uint64_t /*LocData*/, int64_t Addend) {
435   if (Type == ELF::R_HEX_32)
436     return S + Addend;
437   llvm_unreachable("Invalid relocation type");
438 }
439 
440 static bool supportsRISCV(uint64_t Type) {
441   switch (Type) {
442   case ELF::R_RISCV_NONE:
443   case ELF::R_RISCV_32:
444   case ELF::R_RISCV_32_PCREL:
445   case ELF::R_RISCV_64:
446   case ELF::R_RISCV_SET6:
447   case ELF::R_RISCV_SET8:
448   case ELF::R_RISCV_SUB6:
449   case ELF::R_RISCV_ADD8:
450   case ELF::R_RISCV_SUB8:
451   case ELF::R_RISCV_SET16:
452   case ELF::R_RISCV_ADD16:
453   case ELF::R_RISCV_SUB16:
454   case ELF::R_RISCV_SET32:
455   case ELF::R_RISCV_ADD32:
456   case ELF::R_RISCV_SUB32:
457   case ELF::R_RISCV_ADD64:
458   case ELF::R_RISCV_SUB64:
459     // Because the unrelocated value generated by .uleb128 A-B (used by
460     // loclists/rnglists) is meaningful, DebugInfoDWARF does not inspect the
461     // relocations. We declare support for the two relocation types without an
462     // (unreachable) implementation.
463   case ELF::R_RISCV_SET_ULEB128:
464   case ELF::R_RISCV_SUB_ULEB128:
465     return true;
466   default:
467     return false;
468   }
469 }
470 
471 static uint64_t resolveRISCV(uint64_t Type, uint64_t Offset, uint64_t S,
472                              uint64_t LocData, int64_t Addend) {
473   int64_t RA = Addend;
474   uint64_t A = LocData;
475   switch (Type) {
476   case ELF::R_RISCV_NONE:
477     return LocData;
478   case ELF::R_RISCV_32:
479     return (S + RA) & 0xFFFFFFFF;
480   case ELF::R_RISCV_32_PCREL:
481     return (S + RA - Offset) & 0xFFFFFFFF;
482   case ELF::R_RISCV_64:
483     return S + RA;
484   case ELF::R_RISCV_SET6:
485     return (A & 0xC0) | ((S + RA) & 0x3F);
486   case ELF::R_RISCV_SUB6:
487     return (A & 0xC0) | (((A & 0x3F) - (S + RA)) & 0x3F);
488   case ELF::R_RISCV_SET8:
489     return (S + RA) & 0xFF;
490   case ELF::R_RISCV_ADD8:
491     return (A + (S + RA)) & 0xFF;
492   case ELF::R_RISCV_SUB8:
493     return (A - (S + RA)) & 0xFF;
494   case ELF::R_RISCV_SET16:
495     return (S + RA) & 0xFFFF;
496   case ELF::R_RISCV_ADD16:
497     return (A + (S + RA)) & 0xFFFF;
498   case ELF::R_RISCV_SUB16:
499     return (A - (S + RA)) & 0xFFFF;
500   case ELF::R_RISCV_SET32:
501     return (S + RA) & 0xFFFFFFFF;
502   case ELF::R_RISCV_ADD32:
503     return (A + (S + RA)) & 0xFFFFFFFF;
504   case ELF::R_RISCV_SUB32:
505     return (A - (S + RA)) & 0xFFFFFFFF;
506   case ELF::R_RISCV_ADD64:
507     return (A + (S + RA));
508   case ELF::R_RISCV_SUB64:
509     return (A - (S + RA));
510   default:
511     llvm_unreachable("Invalid relocation type");
512   }
513 }
514 
515 static bool supportsCSKY(uint64_t Type) {
516   switch (Type) {
517   case ELF::R_CKCORE_NONE:
518   case ELF::R_CKCORE_ADDR32:
519   case ELF::R_CKCORE_PCREL32:
520     return true;
521   default:
522     return false;
523   }
524 }
525 
526 static uint64_t resolveCSKY(uint64_t Type, uint64_t Offset, uint64_t S,
527                             uint64_t LocData, int64_t Addend) {
528   switch (Type) {
529   case ELF::R_CKCORE_NONE:
530     return LocData;
531   case ELF::R_CKCORE_ADDR32:
532     return (S + Addend) & 0xFFFFFFFF;
533   case ELF::R_CKCORE_PCREL32:
534     return (S + Addend - Offset) & 0xFFFFFFFF;
535   default:
536     llvm_unreachable("Invalid relocation type");
537   }
538 }
539 
540 static bool supportsLoongArch(uint64_t Type) {
541   switch (Type) {
542   case ELF::R_LARCH_NONE:
543   case ELF::R_LARCH_32:
544   case ELF::R_LARCH_32_PCREL:
545   case ELF::R_LARCH_64:
546   case ELF::R_LARCH_ADD6:
547   case ELF::R_LARCH_SUB6:
548   case ELF::R_LARCH_ADD8:
549   case ELF::R_LARCH_SUB8:
550   case ELF::R_LARCH_ADD16:
551   case ELF::R_LARCH_SUB16:
552   case ELF::R_LARCH_ADD32:
553   case ELF::R_LARCH_SUB32:
554   case ELF::R_LARCH_ADD64:
555   case ELF::R_LARCH_SUB64:
556     return true;
557   default:
558     return false;
559   }
560 }
561 
562 static uint64_t resolveLoongArch(uint64_t Type, uint64_t Offset, uint64_t S,
563                                  uint64_t LocData, int64_t Addend) {
564   switch (Type) {
565   case ELF::R_LARCH_NONE:
566     return LocData;
567   case ELF::R_LARCH_32:
568     return (S + Addend) & 0xFFFFFFFF;
569   case ELF::R_LARCH_32_PCREL:
570     return (S + Addend - Offset) & 0xFFFFFFFF;
571   case ELF::R_LARCH_64:
572     return S + Addend;
573   case ELF::R_LARCH_ADD6:
574     return (LocData & 0xC0) | ((LocData + S + Addend) & 0x3F);
575   case ELF::R_LARCH_SUB6:
576     return (LocData & 0xC0) | ((LocData - (S + Addend)) & 0x3F);
577   case ELF::R_LARCH_ADD8:
578     return (LocData + (S + Addend)) & 0xFF;
579   case ELF::R_LARCH_SUB8:
580     return (LocData - (S + Addend)) & 0xFF;
581   case ELF::R_LARCH_ADD16:
582     return (LocData + (S + Addend)) & 0xFFFF;
583   case ELF::R_LARCH_SUB16:
584     return (LocData - (S + Addend)) & 0xFFFF;
585   case ELF::R_LARCH_ADD32:
586     return (LocData + (S + Addend)) & 0xFFFFFFFF;
587   case ELF::R_LARCH_SUB32:
588     return (LocData - (S + Addend)) & 0xFFFFFFFF;
589   case ELF::R_LARCH_ADD64:
590     return (LocData + (S + Addend));
591   case ELF::R_LARCH_SUB64:
592     return (LocData - (S + Addend));
593   default:
594     llvm_unreachable("Invalid relocation type");
595   }
596 }
597 
598 static bool supportsCOFFX86(uint64_t Type) {
599   switch (Type) {
600   case COFF::IMAGE_REL_I386_SECREL:
601   case COFF::IMAGE_REL_I386_DIR32:
602     return true;
603   default:
604     return false;
605   }
606 }
607 
608 static uint64_t resolveCOFFX86(uint64_t Type, uint64_t Offset, uint64_t S,
609                                uint64_t LocData, int64_t /*Addend*/) {
610   switch (Type) {
611   case COFF::IMAGE_REL_I386_SECREL:
612   case COFF::IMAGE_REL_I386_DIR32:
613     return (S + LocData) & 0xFFFFFFFF;
614   default:
615     llvm_unreachable("Invalid relocation type");
616   }
617 }
618 
619 static bool supportsCOFFX86_64(uint64_t Type) {
620   switch (Type) {
621   case COFF::IMAGE_REL_AMD64_SECREL:
622   case COFF::IMAGE_REL_AMD64_ADDR64:
623     return true;
624   default:
625     return false;
626   }
627 }
628 
629 static uint64_t resolveCOFFX86_64(uint64_t Type, uint64_t Offset, uint64_t S,
630                                   uint64_t LocData, int64_t /*Addend*/) {
631   switch (Type) {
632   case COFF::IMAGE_REL_AMD64_SECREL:
633     return (S + LocData) & 0xFFFFFFFF;
634   case COFF::IMAGE_REL_AMD64_ADDR64:
635     return S + LocData;
636   default:
637     llvm_unreachable("Invalid relocation type");
638   }
639 }
640 
641 static bool supportsCOFFARM(uint64_t Type) {
642   switch (Type) {
643   case COFF::IMAGE_REL_ARM_SECREL:
644   case COFF::IMAGE_REL_ARM_ADDR32:
645     return true;
646   default:
647     return false;
648   }
649 }
650 
651 static uint64_t resolveCOFFARM(uint64_t Type, uint64_t Offset, uint64_t S,
652                                uint64_t LocData, int64_t /*Addend*/) {
653   switch (Type) {
654   case COFF::IMAGE_REL_ARM_SECREL:
655   case COFF::IMAGE_REL_ARM_ADDR32:
656     return (S + LocData) & 0xFFFFFFFF;
657   default:
658     llvm_unreachable("Invalid relocation type");
659   }
660 }
661 
662 static bool supportsCOFFARM64(uint64_t Type) {
663   switch (Type) {
664   case COFF::IMAGE_REL_ARM64_SECREL:
665   case COFF::IMAGE_REL_ARM64_ADDR64:
666     return true;
667   default:
668     return false;
669   }
670 }
671 
672 static uint64_t resolveCOFFARM64(uint64_t Type, uint64_t Offset, uint64_t S,
673                                  uint64_t LocData, int64_t /*Addend*/) {
674   switch (Type) {
675   case COFF::IMAGE_REL_ARM64_SECREL:
676     return (S + LocData) & 0xFFFFFFFF;
677   case COFF::IMAGE_REL_ARM64_ADDR64:
678     return S + LocData;
679   default:
680     llvm_unreachable("Invalid relocation type");
681   }
682 }
683 
684 static bool supportsMachOX86_64(uint64_t Type) {
685   return Type == MachO::X86_64_RELOC_UNSIGNED;
686 }
687 
688 static uint64_t resolveMachOX86_64(uint64_t Type, uint64_t Offset, uint64_t S,
689                                    uint64_t LocData, int64_t /*Addend*/) {
690   if (Type == MachO::X86_64_RELOC_UNSIGNED)
691     return S;
692   llvm_unreachable("Invalid relocation type");
693 }
694 
695 static bool supportsWasm32(uint64_t Type) {
696   switch (Type) {
697   case wasm::R_WASM_FUNCTION_INDEX_LEB:
698   case wasm::R_WASM_TABLE_INDEX_SLEB:
699   case wasm::R_WASM_TABLE_INDEX_I32:
700   case wasm::R_WASM_MEMORY_ADDR_LEB:
701   case wasm::R_WASM_MEMORY_ADDR_SLEB:
702   case wasm::R_WASM_MEMORY_ADDR_I32:
703   case wasm::R_WASM_TYPE_INDEX_LEB:
704   case wasm::R_WASM_GLOBAL_INDEX_LEB:
705   case wasm::R_WASM_FUNCTION_OFFSET_I32:
706   case wasm::R_WASM_SECTION_OFFSET_I32:
707   case wasm::R_WASM_TAG_INDEX_LEB:
708   case wasm::R_WASM_GLOBAL_INDEX_I32:
709   case wasm::R_WASM_TABLE_NUMBER_LEB:
710   case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
711     return true;
712   default:
713     return false;
714   }
715 }
716 
717 static bool supportsWasm64(uint64_t Type) {
718   switch (Type) {
719   case wasm::R_WASM_MEMORY_ADDR_LEB64:
720   case wasm::R_WASM_MEMORY_ADDR_SLEB64:
721   case wasm::R_WASM_MEMORY_ADDR_I64:
722   case wasm::R_WASM_TABLE_INDEX_SLEB64:
723   case wasm::R_WASM_TABLE_INDEX_I64:
724   case wasm::R_WASM_FUNCTION_OFFSET_I64:
725     return true;
726   default:
727     return supportsWasm32(Type);
728   }
729 }
730 
731 static uint64_t resolveWasm32(uint64_t Type, uint64_t Offset, uint64_t S,
732                               uint64_t LocData, int64_t /*Addend*/) {
733   switch (Type) {
734   case wasm::R_WASM_FUNCTION_INDEX_LEB:
735   case wasm::R_WASM_TABLE_INDEX_SLEB:
736   case wasm::R_WASM_TABLE_INDEX_I32:
737   case wasm::R_WASM_MEMORY_ADDR_LEB:
738   case wasm::R_WASM_MEMORY_ADDR_SLEB:
739   case wasm::R_WASM_MEMORY_ADDR_I32:
740   case wasm::R_WASM_TYPE_INDEX_LEB:
741   case wasm::R_WASM_GLOBAL_INDEX_LEB:
742   case wasm::R_WASM_FUNCTION_OFFSET_I32:
743   case wasm::R_WASM_SECTION_OFFSET_I32:
744   case wasm::R_WASM_TAG_INDEX_LEB:
745   case wasm::R_WASM_GLOBAL_INDEX_I32:
746   case wasm::R_WASM_TABLE_NUMBER_LEB:
747   case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
748     // For wasm section, its offset at 0 -- ignoring Value
749     return LocData;
750   default:
751     llvm_unreachable("Invalid relocation type");
752   }
753 }
754 
755 static uint64_t resolveWasm64(uint64_t Type, uint64_t Offset, uint64_t S,
756                               uint64_t LocData, int64_t Addend) {
757   switch (Type) {
758   case wasm::R_WASM_MEMORY_ADDR_LEB64:
759   case wasm::R_WASM_MEMORY_ADDR_SLEB64:
760   case wasm::R_WASM_MEMORY_ADDR_I64:
761   case wasm::R_WASM_TABLE_INDEX_SLEB64:
762   case wasm::R_WASM_TABLE_INDEX_I64:
763   case wasm::R_WASM_FUNCTION_OFFSET_I64:
764     // For wasm section, its offset at 0 -- ignoring Value
765     return LocData;
766   default:
767     return resolveWasm32(Type, Offset, S, LocData, Addend);
768   }
769 }
770 
771 std::pair<SupportsRelocation, RelocationResolver>
772 getRelocationResolver(const ObjectFile &Obj) {
773   if (Obj.isCOFF()) {
774     switch (Obj.getArch()) {
775     case Triple::x86_64:
776       return {supportsCOFFX86_64, resolveCOFFX86_64};
777     case Triple::x86:
778       return {supportsCOFFX86, resolveCOFFX86};
779     case Triple::arm:
780     case Triple::thumb:
781       return {supportsCOFFARM, resolveCOFFARM};
782     case Triple::aarch64:
783       return {supportsCOFFARM64, resolveCOFFARM64};
784     default:
785       return {nullptr, nullptr};
786     }
787   } else if (Obj.isELF()) {
788     if (Obj.getBytesInAddress() == 8) {
789       switch (Obj.getArch()) {
790       case Triple::x86_64:
791         return {supportsX86_64, resolveX86_64};
792       case Triple::aarch64:
793       case Triple::aarch64_be:
794         return {supportsAArch64, resolveAArch64};
795       case Triple::bpfel:
796       case Triple::bpfeb:
797         return {supportsBPF, resolveBPF};
798       case Triple::loongarch64:
799         return {supportsLoongArch, resolveLoongArch};
800       case Triple::mips64el:
801       case Triple::mips64:
802         return {supportsMips64, resolveMips64};
803       case Triple::ppc64le:
804       case Triple::ppc64:
805         return {supportsPPC64, resolvePPC64};
806       case Triple::systemz:
807         return {supportsSystemZ, resolveSystemZ};
808       case Triple::sparcv9:
809         return {supportsSparc64, resolveSparc64};
810       case Triple::amdgcn:
811         return {supportsAmdgpu, resolveAmdgpu};
812       case Triple::riscv64:
813         return {supportsRISCV, resolveRISCV};
814       default:
815         if (isAMDGPU(Obj))
816           return {supportsAmdgpu, resolveAmdgpu};
817         return {nullptr, nullptr};
818       }
819     }
820 
821     // 32-bit object file
822     assert(Obj.getBytesInAddress() == 4 &&
823            "Invalid word size in object file");
824 
825     switch (Obj.getArch()) {
826     case Triple::x86:
827       return {supportsX86, resolveX86};
828     case Triple::ppcle:
829     case Triple::ppc:
830       return {supportsPPC32, resolvePPC32};
831     case Triple::arm:
832     case Triple::armeb:
833       return {supportsARM, resolveARM};
834     case Triple::avr:
835       return {supportsAVR, resolveAVR};
836     case Triple::lanai:
837       return {supportsLanai, resolveLanai};
838     case Triple::loongarch32:
839       return {supportsLoongArch, resolveLoongArch};
840     case Triple::mipsel:
841     case Triple::mips:
842       return {supportsMips32, resolveMips32};
843     case Triple::msp430:
844       return {supportsMSP430, resolveMSP430};
845     case Triple::sparc:
846       return {supportsSparc32, resolveSparc32};
847     case Triple::hexagon:
848       return {supportsHexagon, resolveHexagon};
849     case Triple::r600:
850       return {supportsAmdgpu, resolveAmdgpu};
851     case Triple::riscv32:
852       return {supportsRISCV, resolveRISCV};
853     case Triple::csky:
854       return {supportsCSKY, resolveCSKY};
855     default:
856       if (isAMDGPU(Obj))
857         return {supportsAmdgpu, resolveAmdgpu};
858       return {nullptr, nullptr};
859     }
860   } else if (Obj.isMachO()) {
861     if (Obj.getArch() == Triple::x86_64)
862       return {supportsMachOX86_64, resolveMachOX86_64};
863     return {nullptr, nullptr};
864   } else if (Obj.isWasm()) {
865     if (Obj.getArch() == Triple::wasm32)
866       return {supportsWasm32, resolveWasm32};
867     if (Obj.getArch() == Triple::wasm64)
868       return {supportsWasm64, resolveWasm64};
869     return {nullptr, nullptr};
870   }
871 
872   llvm_unreachable("Invalid object file");
873 }
874 
875 uint64_t resolveRelocation(RelocationResolver Resolver, const RelocationRef &R,
876                            uint64_t S, uint64_t LocData) {
877   if (const ObjectFile *Obj = R.getObject()) {
878     int64_t Addend = 0;
879     if (Obj->isELF()) {
880       auto GetRelSectionType = [&]() -> unsigned {
881         if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(Obj))
882           return Elf32LEObj->getRelSection(R.getRawDataRefImpl())->sh_type;
883         if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(Obj))
884           return Elf64LEObj->getRelSection(R.getRawDataRefImpl())->sh_type;
885         if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(Obj))
886           return Elf32BEObj->getRelSection(R.getRawDataRefImpl())->sh_type;
887         auto *Elf64BEObj = cast<ELF64BEObjectFile>(Obj);
888         return Elf64BEObj->getRelSection(R.getRawDataRefImpl())->sh_type;
889       };
890 
891       if (GetRelSectionType() == ELF::SHT_RELA) {
892         Addend = getELFAddend(R);
893         // LoongArch and RISCV relocations use both LocData and Addend.
894         if (Obj->getArch() != Triple::loongarch32 &&
895             Obj->getArch() != Triple::loongarch64 &&
896             Obj->getArch() != Triple::riscv32 &&
897             Obj->getArch() != Triple::riscv64)
898           LocData = 0;
899       }
900     }
901 
902     return Resolver(R.getType(), R.getOffset(), S, LocData, Addend);
903   }
904 
905   // Sometimes the caller might want to use its own specific implementation of
906   // the resolver function. E.g. this is used by LLD when it resolves debug
907   // relocations and assumes that all of them have the same computation (S + A).
908   // The relocation R has no owner object in this case and we don't need to
909   // provide Type and Offset fields. It is also assumed the DataRefImpl.p
910   // contains the addend, provided by the caller.
911   return Resolver(/*Type=*/0, /*Offset=*/0, S, LocData,
912                   R.getRawDataRefImpl().p);
913 }
914 
915 } // namespace object
916 } // namespace llvm
917