blob: 414165c58b6b969605ca097d0fa3a27e57d2b343 [file] [log] [blame]
Fangrui Song4597dce2019-03-22 02:43:11 +00001//===- 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
15namespace llvm {
16namespace object {
17
18static int64_t getELFAddend(RelocationRef R) {
19 Expected<int64_t> AddendOrErr = ELFRelocationRef(R).getAddend();
20 handleAllErrors(AddendOrErr.takeError(), [](const ErrorInfoBase &EI) {
21 report_fatal_error(EI.message());
22 });
23 return *AddendOrErr;
24}
25
26static 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_32:
34 case ELF::R_X86_64_32S:
35 return true;
36 default:
37 return false;
38 }
39}
40
41static uint64_t resolveX86_64(RelocationRef R, uint64_t S, uint64_t A) {
42 switch (R.getType()) {
43 case ELF::R_X86_64_NONE:
44 return A;
45 case ELF::R_X86_64_64:
46 case ELF::R_X86_64_DTPOFF32:
47 case ELF::R_X86_64_DTPOFF64:
48 return S + getELFAddend(R);
49 case ELF::R_X86_64_PC32:
50 return S + getELFAddend(R) - R.getOffset();
51 case ELF::R_X86_64_32:
52 case ELF::R_X86_64_32S:
53 return (S + getELFAddend(R)) & 0xFFFFFFFF;
54 default:
55 llvm_unreachable("Invalid relocation type");
56 }
57}
58
59static bool supportsAArch64(uint64_t Type) {
60 switch (Type) {
61 case ELF::R_AARCH64_ABS32:
62 case ELF::R_AARCH64_ABS64:
63 return true;
64 default:
65 return false;
66 }
67}
68
69static uint64_t resolveAArch64(RelocationRef R, uint64_t S, uint64_t A) {
70 switch (R.getType()) {
71 case ELF::R_AARCH64_ABS32:
72 return (S + getELFAddend(R)) & 0xFFFFFFFF;
73 case ELF::R_AARCH64_ABS64:
74 return S + getELFAddend(R);
75 default:
76 llvm_unreachable("Invalid relocation type");
77 }
78}
79
80static bool supportsBPF(uint64_t Type) {
81 switch (Type) {
82 case ELF::R_BPF_64_32:
83 case ELF::R_BPF_64_64:
84 return true;
85 default:
86 return false;
87 }
88}
89
90static uint64_t resolveBPF(RelocationRef R, uint64_t S, uint64_t A) {
91 switch (R.getType()) {
92 case ELF::R_BPF_64_32:
93 return S & 0xFFFFFFFF;
94 case ELF::R_BPF_64_64:
95 return S;
96 default:
97 llvm_unreachable("Invalid relocation type");
98 }
99}
100
101static bool supportsMips64(uint64_t Type) {
102 switch (Type) {
103 case ELF::R_MIPS_32:
104 case ELF::R_MIPS_64:
105 case ELF::R_MIPS_TLS_DTPREL64:
106 return true;
107 default:
108 return false;
109 }
110}
111
112static uint64_t resolveMips64(RelocationRef R, uint64_t S, uint64_t A) {
113 switch (R.getType()) {
114 case ELF::R_MIPS_32:
115 return (S + getELFAddend(R)) & 0xFFFFFFFF;
116 case ELF::R_MIPS_64:
117 return S + getELFAddend(R);
118 case ELF::R_MIPS_TLS_DTPREL64:
119 return S + getELFAddend(R) - 0x8000;
120 default:
121 llvm_unreachable("Invalid relocation type");
122 }
123}
124
125static bool supportsPPC64(uint64_t Type) {
126 switch (Type) {
127 case ELF::R_PPC64_ADDR32:
128 case ELF::R_PPC64_ADDR64:
129 return true;
130 default:
131 return false;
132 }
133}
134
135static uint64_t resolvePPC64(RelocationRef R, uint64_t S, uint64_t A) {
136 switch (R.getType()) {
137 case ELF::R_PPC64_ADDR32:
138 return (S + getELFAddend(R)) & 0xFFFFFFFF;
139 case ELF::R_PPC64_ADDR64:
140 return S + getELFAddend(R);
141 default:
142 llvm_unreachable("Invalid relocation type");
143 }
144}
145
146static bool supportsSystemZ(uint64_t Type) {
147 switch (Type) {
148 case ELF::R_390_32:
149 case ELF::R_390_64:
150 return true;
151 default:
152 return false;
153 }
154}
155
156static uint64_t resolveSystemZ(RelocationRef R, uint64_t S, uint64_t A) {
157 switch (R.getType()) {
158 case ELF::R_390_32:
159 return (S + getELFAddend(R)) & 0xFFFFFFFF;
160 case ELF::R_390_64:
161 return S + getELFAddend(R);
162 default:
163 llvm_unreachable("Invalid relocation type");
164 }
165}
166
167static bool supportsSparc64(uint64_t Type) {
168 switch (Type) {
169 case ELF::R_SPARC_32:
170 case ELF::R_SPARC_64:
171 case ELF::R_SPARC_UA32:
172 case ELF::R_SPARC_UA64:
173 return true;
174 default:
175 return false;
176 }
177}
178
179static uint64_t resolveSparc64(RelocationRef R, uint64_t S, uint64_t A) {
180 switch (R.getType()) {
181 case ELF::R_SPARC_32:
182 case ELF::R_SPARC_64:
183 case ELF::R_SPARC_UA32:
184 case ELF::R_SPARC_UA64:
185 return S + getELFAddend(R);
186 default:
187 llvm_unreachable("Invalid relocation type");
188 }
189}
190
191static bool supportsAmdgpu(uint64_t Type) {
192 switch (Type) {
193 case ELF::R_AMDGPU_ABS32:
194 case ELF::R_AMDGPU_ABS64:
195 return true;
196 default:
197 return false;
198 }
199}
200
201static uint64_t resolveAmdgpu(RelocationRef R, uint64_t S, uint64_t A) {
202 switch (R.getType()) {
203 case ELF::R_AMDGPU_ABS32:
204 case ELF::R_AMDGPU_ABS64:
205 return S + getELFAddend(R);
206 default:
207 llvm_unreachable("Invalid relocation type");
208 }
209}
210
211static bool supportsX86(uint64_t Type) {
212 switch (Type) {
213 case ELF::R_386_NONE:
214 case ELF::R_386_32:
215 case ELF::R_386_PC32:
216 return true;
217 default:
218 return false;
219 }
220}
221
222static uint64_t resolveX86(RelocationRef R, uint64_t S, uint64_t A) {
223 switch (R.getType()) {
224 case ELF::R_386_NONE:
225 return A;
226 case ELF::R_386_32:
227 return S + A;
228 case ELF::R_386_PC32:
229 return S - R.getOffset() + A;
230 default:
231 llvm_unreachable("Invalid relocation type");
232 }
233}
234
235static bool supportsPPC32(uint64_t Type) {
236 return Type == ELF::R_PPC_ADDR32;
237}
238
239static uint64_t resolvePPC32(RelocationRef R, uint64_t S, uint64_t A) {
240 if (R.getType() == ELF::R_PPC_ADDR32)
241 return (S + getELFAddend(R)) & 0xFFFFFFFF;
242 llvm_unreachable("Invalid relocation type");
243}
244
245static bool supportsARM(uint64_t Type) {
246 return Type == ELF::R_ARM_ABS32;
247}
248
249static uint64_t resolveARM(RelocationRef R, uint64_t S, uint64_t A) {
250 if (R.getType() == ELF::R_ARM_ABS32)
251 return (S + A) & 0xFFFFFFFF;
252 llvm_unreachable("Invalid relocation type");
253}
254
255static bool supportsAVR(uint64_t Type) {
256 switch (Type) {
257 case ELF::R_AVR_16:
258 case ELF::R_AVR_32:
259 return true;
260 default:
261 return false;
262 }
263}
264
265static uint64_t resolveAVR(RelocationRef R, uint64_t S, uint64_t A) {
266 switch (R.getType()) {
267 case ELF::R_AVR_16:
268 return (S + getELFAddend(R)) & 0xFFFF;
269 case ELF::R_AVR_32:
270 return (S + getELFAddend(R)) & 0xFFFFFFFF;
271 default:
272 llvm_unreachable("Invalid relocation type");
273 }
274}
275
276static bool supportsLanai(uint64_t Type) {
277 return Type == ELF::R_LANAI_32;
278}
279
280static uint64_t resolveLanai(RelocationRef R, uint64_t S, uint64_t A) {
281 if (R.getType() == ELF::R_LANAI_32)
282 return (S + getELFAddend(R)) & 0xFFFFFFFF;
283 llvm_unreachable("Invalid relocation type");
284}
285
286static bool supportsMips32(uint64_t Type) {
287 switch (Type) {
288 case ELF::R_MIPS_32:
289 case ELF::R_MIPS_TLS_DTPREL32:
290 return true;
291 default:
292 return false;
293 }
294}
295
296static uint64_t resolveMips32(RelocationRef R, uint64_t S, uint64_t A) {
297 // FIXME: Take in account implicit addends to get correct results.
298 uint32_t Rel = R.getType();
299 if (Rel == ELF::R_MIPS_32)
300 return (S + A) & 0xFFFFFFFF;
301 if (Rel == ELF::R_MIPS_TLS_DTPREL32)
302 return (S + A) & 0xFFFFFFFF;
303 llvm_unreachable("Invalid relocation type");
304}
305
306static bool supportsSparc32(uint64_t Type) {
307 switch (Type) {
308 case ELF::R_SPARC_32:
309 case ELF::R_SPARC_UA32:
310 return true;
311 default:
312 return false;
313 }
314}
315
316static uint64_t resolveSparc32(RelocationRef R, uint64_t S, uint64_t A) {
317 uint32_t Rel = R.getType();
318 if (Rel == ELF::R_SPARC_32 || Rel == ELF::R_SPARC_UA32)
319 return S + getELFAddend(R);
320 return A;
321}
322
323static bool supportsHexagon(uint64_t Type) {
324 return Type == ELF::R_HEX_32;
325}
326
327static uint64_t resolveHexagon(RelocationRef R, uint64_t S, uint64_t A) {
328 if (R.getType() == ELF::R_HEX_32)
329 return S + getELFAddend(R);
330 llvm_unreachable("Invalid relocation type");
331}
332
333static bool supportsCOFFX86(uint64_t Type) {
334 switch (Type) {
335 case COFF::IMAGE_REL_I386_SECREL:
336 case COFF::IMAGE_REL_I386_DIR32:
337 return true;
338 default:
339 return false;
340 }
341}
342
343static uint64_t resolveCOFFX86(RelocationRef R, uint64_t S, uint64_t A) {
344 switch (R.getType()) {
345 case COFF::IMAGE_REL_I386_SECREL:
346 case COFF::IMAGE_REL_I386_DIR32:
347 return (S + A) & 0xFFFFFFFF;
348 default:
349 llvm_unreachable("Invalid relocation type");
350 }
351}
352
353static bool supportsCOFFX86_64(uint64_t Type) {
354 switch (Type) {
355 case COFF::IMAGE_REL_AMD64_SECREL:
356 case COFF::IMAGE_REL_AMD64_ADDR64:
357 return true;
358 default:
359 return false;
360 }
361}
362
363static uint64_t resolveCOFFX86_64(RelocationRef R, uint64_t S, uint64_t A) {
364 switch (R.getType()) {
365 case COFF::IMAGE_REL_AMD64_SECREL:
366 return (S + A) & 0xFFFFFFFF;
367 case COFF::IMAGE_REL_AMD64_ADDR64:
368 return S + A;
369 default:
370 llvm_unreachable("Invalid relocation type");
371 }
372}
373
374static bool supportsMachOX86_64(uint64_t Type) {
375 return Type == MachO::X86_64_RELOC_UNSIGNED;
376}
377
378static uint64_t resolveMachOX86_64(RelocationRef R, uint64_t S, uint64_t A) {
379 if (R.getType() == MachO::X86_64_RELOC_UNSIGNED)
380 return S;
381 llvm_unreachable("Invalid relocation type");
382}
383
384static bool supportsWasm32(uint64_t Type) {
385 switch (Type) {
386 case wasm::R_WASM_FUNCTION_INDEX_LEB:
387 case wasm::R_WASM_TABLE_INDEX_SLEB:
388 case wasm::R_WASM_TABLE_INDEX_I32:
389 case wasm::R_WASM_MEMORY_ADDR_LEB:
390 case wasm::R_WASM_MEMORY_ADDR_SLEB:
391 case wasm::R_WASM_MEMORY_ADDR_I32:
392 case wasm::R_WASM_TYPE_INDEX_LEB:
393 case wasm::R_WASM_GLOBAL_INDEX_LEB:
394 case wasm::R_WASM_FUNCTION_OFFSET_I32:
395 case wasm::R_WASM_SECTION_OFFSET_I32:
396 case wasm::R_WASM_EVENT_INDEX_LEB:
397 return true;
398 default:
399 return false;
400 }
401}
402
403static uint64_t resolveWasm32(RelocationRef R, uint64_t S, uint64_t A) {
404 switch (R.getType()) {
405 case wasm::R_WASM_FUNCTION_INDEX_LEB:
406 case wasm::R_WASM_TABLE_INDEX_SLEB:
407 case wasm::R_WASM_TABLE_INDEX_I32:
408 case wasm::R_WASM_MEMORY_ADDR_LEB:
409 case wasm::R_WASM_MEMORY_ADDR_SLEB:
410 case wasm::R_WASM_MEMORY_ADDR_I32:
411 case wasm::R_WASM_TYPE_INDEX_LEB:
412 case wasm::R_WASM_GLOBAL_INDEX_LEB:
413 case wasm::R_WASM_FUNCTION_OFFSET_I32:
414 case wasm::R_WASM_SECTION_OFFSET_I32:
415 case wasm::R_WASM_EVENT_INDEX_LEB:
416 // For wasm section, its offset at 0 -- ignoring Value
417 return A;
418 default:
419 llvm_unreachable("Invalid relocation type");
420 }
421}
422
423std::pair<bool (*)(uint64_t), RelocationResolver>
424getRelocationResolver(const ObjectFile &Obj) {
425 if (Obj.isCOFF()) {
426 if (Obj.getBytesInAddress() == 8)
427 return {supportsCOFFX86_64, resolveCOFFX86_64};
428 return {supportsCOFFX86, resolveCOFFX86};
429 } else if (Obj.isELF()) {
430 if (Obj.getBytesInAddress() == 8) {
431 switch (Obj.getArch()) {
432 case Triple::x86_64:
433 return {supportsX86_64, resolveX86_64};
434 case Triple::aarch64:
435 case Triple::aarch64_be:
436 return {supportsAArch64, resolveAArch64};
437 case Triple::bpfel:
438 case Triple::bpfeb:
439 return {supportsBPF, resolveBPF};
440 case Triple::mips64el:
441 case Triple::mips64:
442 return {supportsMips64, resolveMips64};
443 case Triple::ppc64le:
444 case Triple::ppc64:
445 return {supportsPPC64, resolvePPC64};
446 case Triple::systemz:
447 return {supportsSystemZ, resolveSystemZ};
448 case Triple::sparcv9:
449 return {supportsSparc64, resolveSparc64};
450 case Triple::amdgcn:
451 return {supportsAmdgpu, resolveAmdgpu};
452 default:
453 return {nullptr, nullptr};
454 }
455 }
456
457 // 32-bit object file
458 assert(Obj.getBytesInAddress() == 4 &&
459 "Invalid word size in object file");
460
461 switch (Obj.getArch()) {
462 case Triple::x86:
463 return {supportsX86, resolveX86};
464 case Triple::ppc:
465 return {supportsPPC32, resolvePPC32};
466 case Triple::arm:
467 case Triple::armeb:
468 return {supportsARM, resolveARM};
469 case Triple::avr:
470 return {supportsAVR, resolveAVR};
471 case Triple::lanai:
472 return {supportsLanai, resolveLanai};
473 case Triple::mipsel:
474 case Triple::mips:
475 return {supportsMips32, resolveMips32};
476 case Triple::sparc:
477 return {supportsSparc32, resolveSparc32};
478 case Triple::hexagon:
479 return {supportsHexagon, resolveHexagon};
480 default:
481 return {nullptr, nullptr};
482 }
483 } else if (Obj.isMachO()) {
484 if (Obj.getArch() == Triple::x86_64)
485 return {supportsMachOX86_64, resolveMachOX86_64};
486 return {nullptr, nullptr};
487 } else if (Obj.isWasm()) {
488 if (Obj.getArch() == Triple::wasm32)
489 return {supportsWasm32, resolveWasm32};
490 return {nullptr, nullptr};
491 }
492
493 llvm_unreachable("Invalid object file");
494}
495
496} // namespace object
497} // namespace llvm