Recommit [NFC] Better encapsulation of llvm::Optional Storage
[llvm-complete.git] / include / llvm / Object / RelocVisitor.h
blob76f3fab2febb8471d586c32337ef9f1498867685
1 //===- RelocVisitor.h - Visitor for object file relocations -----*- 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 provides a wrapper around all the different types of relocations
10 // in different file formats, such that a client can handle them in a unified
11 // manner by only implementing a minimal number of functions.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_OBJECT_RELOCVISITOR_H
16 #define LLVM_OBJECT_RELOCVISITOR_H
18 #include "llvm/ADT/Triple.h"
19 #include "llvm/BinaryFormat/ELF.h"
20 #include "llvm/BinaryFormat/MachO.h"
21 #include "llvm/Object/COFF.h"
22 #include "llvm/Object/ELFObjectFile.h"
23 #include "llvm/Object/MachO.h"
24 #include "llvm/Object/ObjectFile.h"
25 #include "llvm/Object/Wasm.h"
26 #include "llvm/Support/Casting.h"
27 #include "llvm/Support/ErrorHandling.h"
28 #include <cstdint>
29 #include <system_error>
31 namespace llvm {
32 namespace object {
34 /// Base class for object file relocation visitors.
35 class RelocVisitor {
36 public:
37 explicit RelocVisitor(const ObjectFile &Obj) : ObjToVisit(Obj) {}
39 // TODO: Should handle multiple applied relocations via either passing in the
40 // previously computed value or just count paired relocations as a single
41 // visit.
42 uint64_t visit(uint32_t Rel, RelocationRef R, uint64_t Value = 0) {
43 if (isa<ELFObjectFileBase>(ObjToVisit))
44 return visitELF(Rel, R, Value);
45 if (isa<COFFObjectFile>(ObjToVisit))
46 return visitCOFF(Rel, R, Value);
47 if (isa<MachOObjectFile>(ObjToVisit))
48 return visitMachO(Rel, R, Value);
49 if (isa<WasmObjectFile>(ObjToVisit))
50 return visitWasm(Rel, R, Value);
52 HasError = true;
53 return 0;
56 bool error() { return HasError; }
58 private:
59 const ObjectFile &ObjToVisit;
60 bool HasError = false;
62 uint64_t visitELF(uint32_t Rel, RelocationRef R, uint64_t Value) {
63 if (ObjToVisit.getBytesInAddress() == 8) { // 64-bit object file
64 switch (ObjToVisit.getArch()) {
65 case Triple::x86_64:
66 return visitX86_64(Rel, R, Value);
67 case Triple::aarch64:
68 case Triple::aarch64_be:
69 return visitAarch64(Rel, R, Value);
70 case Triple::bpfel:
71 case Triple::bpfeb:
72 return visitBpf(Rel, R, Value);
73 case Triple::mips64el:
74 case Triple::mips64:
75 return visitMips64(Rel, R, Value);
76 case Triple::ppc64le:
77 case Triple::ppc64:
78 return visitPPC64(Rel, R, Value);
79 case Triple::systemz:
80 return visitSystemz(Rel, R, Value);
81 case Triple::sparcv9:
82 return visitSparc64(Rel, R, Value);
83 case Triple::amdgcn:
84 return visitAmdgpu(Rel, R, Value);
85 default:
86 HasError = true;
87 return 0;
91 // 32-bit object file
92 assert(ObjToVisit.getBytesInAddress() == 4 &&
93 "Invalid word size in object file");
95 switch (ObjToVisit.getArch()) {
96 case Triple::x86:
97 return visitX86(Rel, R, Value);
98 case Triple::ppc:
99 return visitPPC32(Rel, R, Value);
100 case Triple::arm:
101 case Triple::armeb:
102 return visitARM(Rel, R, Value);
103 case Triple::avr:
104 return visitAVR(Rel, R, Value);
105 case Triple::lanai:
106 return visitLanai(Rel, R, Value);
107 case Triple::mipsel:
108 case Triple::mips:
109 return visitMips32(Rel, R, Value);
110 case Triple::sparc:
111 return visitSparc32(Rel, R, Value);
112 case Triple::hexagon:
113 return visitHexagon(Rel, R, Value);
114 default:
115 HasError = true;
116 return 0;
120 int64_t getELFAddend(RelocationRef R) {
121 Expected<int64_t> AddendOrErr = ELFRelocationRef(R).getAddend();
122 handleAllErrors(AddendOrErr.takeError(), [](const ErrorInfoBase &EI) {
123 report_fatal_error(EI.message());
125 return *AddendOrErr;
128 uint64_t visitX86_64(uint32_t Rel, RelocationRef R, uint64_t Value) {
129 switch (Rel) {
130 case ELF::R_X86_64_NONE:
131 return 0;
132 case ELF::R_X86_64_64:
133 case ELF::R_X86_64_DTPOFF32:
134 case ELF::R_X86_64_DTPOFF64:
135 return Value + getELFAddend(R);
136 case ELF::R_X86_64_PC32:
137 return Value + getELFAddend(R) - R.getOffset();
138 case ELF::R_X86_64_32:
139 case ELF::R_X86_64_32S:
140 return (Value + getELFAddend(R)) & 0xFFFFFFFF;
142 HasError = true;
143 return 0;
146 uint64_t visitAarch64(uint32_t Rel, RelocationRef R, uint64_t Value) {
147 switch (Rel) {
148 case ELF::R_AARCH64_ABS32: {
149 int64_t Res = Value + getELFAddend(R);
150 if (Res < INT32_MIN || Res > UINT32_MAX)
151 HasError = true;
152 return static_cast<uint32_t>(Res);
154 case ELF::R_AARCH64_ABS64:
155 return Value + getELFAddend(R);
157 HasError = true;
158 return 0;
161 uint64_t visitBpf(uint32_t Rel, RelocationRef R, uint64_t Value) {
162 switch (Rel) {
163 case ELF::R_BPF_64_32:
164 return Value & 0xFFFFFFFF;
165 case ELF::R_BPF_64_64:
166 return Value;
168 HasError = true;
169 return 0;
172 uint64_t visitMips64(uint32_t Rel, RelocationRef R, uint64_t Value) {
173 switch (Rel) {
174 case ELF::R_MIPS_32:
175 return (Value + getELFAddend(R)) & 0xFFFFFFFF;
176 case ELF::R_MIPS_64:
177 return Value + getELFAddend(R);
178 case ELF::R_MIPS_TLS_DTPREL64:
179 return Value + getELFAddend(R) - 0x8000;
181 HasError = true;
182 return 0;
185 uint64_t visitPPC64(uint32_t Rel, RelocationRef R, uint64_t Value) {
186 switch (Rel) {
187 case ELF::R_PPC64_ADDR32:
188 return (Value + getELFAddend(R)) & 0xFFFFFFFF;
189 case ELF::R_PPC64_ADDR64:
190 return Value + getELFAddend(R);
192 HasError = true;
193 return 0;
196 uint64_t visitSystemz(uint32_t Rel, RelocationRef R, uint64_t Value) {
197 switch (Rel) {
198 case ELF::R_390_32: {
199 int64_t Res = Value + getELFAddend(R);
200 if (Res < INT32_MIN || Res > UINT32_MAX)
201 HasError = true;
202 return static_cast<uint32_t>(Res);
204 case ELF::R_390_64:
205 return Value + getELFAddend(R);
207 HasError = true;
208 return 0;
211 uint64_t visitSparc64(uint32_t Rel, RelocationRef R, uint64_t Value) {
212 switch (Rel) {
213 case ELF::R_SPARC_32:
214 case ELF::R_SPARC_64:
215 case ELF::R_SPARC_UA32:
216 case ELF::R_SPARC_UA64:
217 return Value + getELFAddend(R);
219 HasError = true;
220 return 0;
223 uint64_t visitAmdgpu(uint32_t Rel, RelocationRef R, uint64_t Value) {
224 switch (Rel) {
225 case ELF::R_AMDGPU_ABS32:
226 case ELF::R_AMDGPU_ABS64:
227 return Value + getELFAddend(R);
229 HasError = true;
230 return 0;
233 uint64_t visitX86(uint32_t Rel, RelocationRef R, uint64_t Value) {
234 switch (Rel) {
235 case ELF::R_386_NONE:
236 return 0;
237 case ELF::R_386_32:
238 return Value;
239 case ELF::R_386_PC32:
240 return Value - R.getOffset();
242 HasError = true;
243 return 0;
246 uint64_t visitPPC32(uint32_t Rel, RelocationRef R, uint64_t Value) {
247 if (Rel == ELF::R_PPC_ADDR32)
248 return (Value + getELFAddend(R)) & 0xFFFFFFFF;
249 HasError = true;
250 return 0;
253 uint64_t visitARM(uint32_t Rel, RelocationRef R, uint64_t Value) {
254 if (Rel == ELF::R_ARM_ABS32) {
255 if ((int64_t)Value < INT32_MIN || (int64_t)Value > UINT32_MAX)
256 HasError = true;
257 return static_cast<uint32_t>(Value);
259 HasError = true;
260 return 0;
263 uint64_t visitAVR(uint32_t Rel, RelocationRef R, uint64_t Value) {
264 if (Rel == ELF::R_AVR_16) {
265 return (Value + getELFAddend(R)) & 0xFFFF;
266 } else if (Rel == ELF::R_AVR_32) {
267 return (Value + getELFAddend(R)) & 0xFFFFFFFF;
269 HasError = true;
270 return 0;
273 uint64_t visitLanai(uint32_t Rel, RelocationRef R, uint64_t Value) {
274 if (Rel == ELF::R_LANAI_32)
275 return (Value + getELFAddend(R)) & 0xFFFFFFFF;
276 HasError = true;
277 return 0;
280 uint64_t visitMips32(uint32_t Rel, RelocationRef R, uint64_t Value) {
281 // FIXME: Take in account implicit addends to get correct results.
282 if (Rel == ELF::R_MIPS_32)
283 return Value & 0xFFFFFFFF;
284 if (Rel == ELF::R_MIPS_TLS_DTPREL32)
285 return Value & 0xFFFFFFFF;
286 HasError = true;
287 return 0;
290 uint64_t visitSparc32(uint32_t Rel, RelocationRef R, uint64_t Value) {
291 if (Rel == ELF::R_SPARC_32 || Rel == ELF::R_SPARC_UA32)
292 return Value + getELFAddend(R);
293 HasError = true;
294 return 0;
297 uint64_t visitHexagon(uint32_t Rel, RelocationRef R, uint64_t Value) {
298 if (Rel == ELF::R_HEX_32)
299 return Value + getELFAddend(R);
300 HasError = true;
301 return 0;
304 uint64_t visitCOFF(uint32_t Rel, RelocationRef R, uint64_t Value) {
305 switch (ObjToVisit.getArch()) {
306 case Triple::x86:
307 switch (Rel) {
308 case COFF::IMAGE_REL_I386_SECREL:
309 case COFF::IMAGE_REL_I386_DIR32:
310 return static_cast<uint32_t>(Value);
312 break;
313 case Triple::x86_64:
314 switch (Rel) {
315 case COFF::IMAGE_REL_AMD64_SECREL:
316 return static_cast<uint32_t>(Value);
317 case COFF::IMAGE_REL_AMD64_ADDR64:
318 return Value;
320 break;
321 default:
322 break;
324 HasError = true;
325 return 0;
328 uint64_t visitMachO(uint32_t Rel, RelocationRef R, uint64_t Value) {
329 if (ObjToVisit.getArch() == Triple::x86_64 &&
330 Rel == MachO::X86_64_RELOC_UNSIGNED)
331 return Value;
332 HasError = true;
333 return 0;
336 uint64_t visitWasm(uint32_t Rel, RelocationRef R, uint64_t Value) {
337 if (ObjToVisit.getArch() == Triple::wasm32) {
338 switch (Rel) {
339 case wasm::R_WASM_FUNCTION_INDEX_LEB:
340 case wasm::R_WASM_TABLE_INDEX_SLEB:
341 case wasm::R_WASM_TABLE_INDEX_I32:
342 case wasm::R_WASM_MEMORY_ADDR_LEB:
343 case wasm::R_WASM_MEMORY_ADDR_SLEB:
344 case wasm::R_WASM_MEMORY_ADDR_I32:
345 case wasm::R_WASM_TYPE_INDEX_LEB:
346 case wasm::R_WASM_GLOBAL_INDEX_LEB:
347 case wasm::R_WASM_FUNCTION_OFFSET_I32:
348 case wasm::R_WASM_SECTION_OFFSET_I32:
349 case wasm::R_WASM_EVENT_INDEX_LEB:
350 // For wasm section, its offset at 0 -- ignoring Value
351 return 0;
354 HasError = true;
355 return 0;
359 } // end namespace object
360 } // end namespace llvm
362 #endif // LLVM_OBJECT_RELOCVISITOR_H