Line data Source code
1 : //===- RelocVisitor.h - Visitor for object file relocations -----*- C++ -*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // This file provides a wrapper around all the different types of relocations
11 : // in different file formats, such that a client can handle them in a unified
12 : // manner by only implementing a minimal number of functions.
13 : //
14 : //===----------------------------------------------------------------------===//
15 :
16 : #ifndef LLVM_OBJECT_RELOCVISITOR_H
17 : #define LLVM_OBJECT_RELOCVISITOR_H
18 :
19 : #include "llvm/ADT/Triple.h"
20 : #include "llvm/BinaryFormat/ELF.h"
21 : #include "llvm/BinaryFormat/MachO.h"
22 : #include "llvm/Object/COFF.h"
23 : #include "llvm/Object/ELFObjectFile.h"
24 : #include "llvm/Object/MachO.h"
25 : #include "llvm/Object/ObjectFile.h"
26 : #include "llvm/Object/Wasm.h"
27 : #include "llvm/Support/Casting.h"
28 : #include "llvm/Support/ErrorHandling.h"
29 : #include <cstdint>
30 : #include <system_error>
31 :
32 : namespace llvm {
33 : namespace object {
34 :
35 : /// Base class for object file relocation visitors.
36 : class RelocVisitor {
37 : public:
38 12334 : explicit RelocVisitor(const ObjectFile &Obj) : ObjToVisit(Obj) {}
39 :
40 : // TODO: Should handle multiple applied relocations via either passing in the
41 : // previously computed value or just count paired relocations as a single
42 : // visit.
43 12334 : uint64_t visit(uint32_t Rel, RelocationRef R, uint64_t Value = 0) {
44 24668 : if (isa<ELFObjectFileBase>(ObjToVisit))
45 12159 : return visitELF(Rel, R, Value);
46 175 : if (isa<COFFObjectFile>(ObjToVisit))
47 148 : return visitCOFF(Rel, R, Value);
48 27 : if (isa<MachOObjectFile>(ObjToVisit))
49 : return visitMachO(Rel, R, Value);
50 14 : if (isa<WasmObjectFile>(ObjToVisit))
51 : return visitWasm(Rel, R, Value);
52 :
53 0 : HasError = true;
54 0 : return 0;
55 : }
56 :
57 0 : bool error() { return HasError; }
58 :
59 : private:
60 : const ObjectFile &ObjToVisit;
61 : bool HasError = false;
62 :
63 12159 : uint64_t visitELF(uint32_t Rel, RelocationRef R, uint64_t Value) {
64 12159 : if (ObjToVisit.getBytesInAddress() == 8) { // 64-bit object file
65 11608 : switch (ObjToVisit.getArch()) {
66 11263 : case Triple::x86_64:
67 11263 : return visitX86_64(Rel, R, Value);
68 133 : case Triple::aarch64:
69 : case Triple::aarch64_be:
70 133 : return visitAarch64(Rel, R, Value);
71 32 : case Triple::bpfel:
72 : case Triple::bpfeb:
73 : return visitBpf(Rel, R, Value);
74 24 : case Triple::mips64el:
75 : case Triple::mips64:
76 24 : return visitMips64(Rel, R, Value);
77 0 : case Triple::ppc64le:
78 : case Triple::ppc64:
79 0 : return visitPPC64(Rel, R, Value);
80 31 : case Triple::systemz:
81 31 : return visitSystemz(Rel, R, Value);
82 22 : case Triple::sparcv9:
83 22 : return visitSparc64(Rel, R, Value);
84 103 : case Triple::amdgcn:
85 103 : return visitAmdgpu(Rel, R, Value);
86 0 : default:
87 0 : HasError = true;
88 0 : return 0;
89 : }
90 : }
91 :
92 : // 32-bit object file
93 : assert(ObjToVisit.getBytesInAddress() == 4 &&
94 : "Invalid word size in object file");
95 :
96 551 : switch (ObjToVisit.getArch()) {
97 251 : case Triple::x86:
98 251 : return visitX86(Rel, R, Value);
99 0 : case Triple::ppc:
100 0 : return visitPPC32(Rel, R, Value);
101 157 : case Triple::arm:
102 : case Triple::armeb:
103 : return visitARM(Rel, R, Value);
104 0 : case Triple::lanai:
105 0 : return visitLanai(Rel, R, Value);
106 94 : case Triple::mipsel:
107 : case Triple::mips:
108 : return visitMips32(Rel, R, Value);
109 10 : case Triple::sparc:
110 10 : return visitSparc32(Rel, R, Value);
111 30 : case Triple::hexagon:
112 30 : return visitHexagon(Rel, R, Value);
113 9 : default:
114 9 : HasError = true;
115 9 : return 0;
116 : }
117 : }
118 :
119 11611 : int64_t getELFAddend(RelocationRef R) {
120 11611 : Expected<int64_t> AddendOrErr = ELFRelocationRef(R).getAddend();
121 11611 : handleAllErrors(AddendOrErr.takeError(), [](const ErrorInfoBase &EI) {
122 : report_fatal_error(EI.message());
123 : });
124 11610 : return *AddendOrErr;
125 : }
126 :
127 11263 : uint64_t visitX86_64(uint32_t Rel, RelocationRef R, uint64_t Value) {
128 11263 : switch (Rel) {
129 : case ELF::R_X86_64_NONE:
130 : return 0;
131 2013 : case ELF::R_X86_64_64:
132 2013 : return Value + getELFAddend(R);
133 0 : case ELF::R_X86_64_PC32:
134 0 : return Value + getELFAddend(R) - R.getOffset();
135 9245 : case ELF::R_X86_64_32:
136 : case ELF::R_X86_64_32S:
137 9245 : return (Value + getELFAddend(R)) & 0xFFFFFFFF;
138 : }
139 5 : HasError = true;
140 5 : return 0;
141 : }
142 :
143 133 : uint64_t visitAarch64(uint32_t Rel, RelocationRef R, uint64_t Value) {
144 133 : switch (Rel) {
145 95 : case ELF::R_AARCH64_ABS32: {
146 95 : int64_t Res = Value + getELFAddend(R);
147 95 : if (Res < INT32_MIN || Res > UINT32_MAX)
148 0 : HasError = true;
149 95 : return static_cast<uint32_t>(Res);
150 : }
151 38 : case ELF::R_AARCH64_ABS64:
152 38 : return Value + getELFAddend(R);
153 : }
154 0 : HasError = true;
155 0 : return 0;
156 : }
157 :
158 0 : uint64_t visitBpf(uint32_t Rel, RelocationRef R, uint64_t Value) {
159 32 : switch (Rel) {
160 24 : case ELF::R_BPF_64_32:
161 24 : return Value & 0xFFFFFFFF;
162 : case ELF::R_BPF_64_64:
163 : return Value;
164 : }
165 0 : HasError = true;
166 0 : return 0;
167 : }
168 :
169 24 : uint64_t visitMips64(uint32_t Rel, RelocationRef R, uint64_t Value) {
170 24 : switch (Rel) {
171 16 : case ELF::R_MIPS_32:
172 16 : return (Value + getELFAddend(R)) & 0xFFFFFFFF;
173 7 : case ELF::R_MIPS_64:
174 7 : return Value + getELFAddend(R);
175 1 : case ELF::R_MIPS_TLS_DTPREL64:
176 1 : return Value + getELFAddend(R) - 0x8000;
177 : }
178 0 : HasError = true;
179 0 : return 0;
180 : }
181 :
182 0 : uint64_t visitPPC64(uint32_t Rel, RelocationRef R, uint64_t Value) {
183 0 : switch (Rel) {
184 0 : case ELF::R_PPC64_ADDR32:
185 0 : return (Value + getELFAddend(R)) & 0xFFFFFFFF;
186 0 : case ELF::R_PPC64_ADDR64:
187 0 : return Value + getELFAddend(R);
188 : }
189 0 : HasError = true;
190 0 : return 0;
191 : }
192 :
193 31 : uint64_t visitSystemz(uint32_t Rel, RelocationRef R, uint64_t Value) {
194 31 : switch (Rel) {
195 22 : case ELF::R_390_32: {
196 22 : int64_t Res = Value + getELFAddend(R);
197 22 : if (Res < INT32_MIN || Res > UINT32_MAX)
198 0 : HasError = true;
199 22 : return static_cast<uint32_t>(Res);
200 : }
201 9 : case ELF::R_390_64:
202 9 : return Value + getELFAddend(R);
203 : }
204 0 : HasError = true;
205 0 : return 0;
206 : }
207 :
208 22 : uint64_t visitSparc64(uint32_t Rel, RelocationRef R, uint64_t Value) {
209 : switch (Rel) {
210 22 : case ELF::R_SPARC_32:
211 : case ELF::R_SPARC_64:
212 : case ELF::R_SPARC_UA32:
213 : case ELF::R_SPARC_UA64:
214 22 : return Value + getELFAddend(R);
215 : }
216 0 : HasError = true;
217 0 : return 0;
218 : }
219 :
220 : uint64_t visitAmdgpu(uint32_t Rel, RelocationRef R, uint64_t Value) {
221 103 : switch (Rel) {
222 103 : case ELF::R_AMDGPU_ABS32:
223 : case ELF::R_AMDGPU_ABS64:
224 103 : return Value + getELFAddend(R);
225 : }
226 0 : HasError = true;
227 : return 0;
228 : }
229 :
230 0 : uint64_t visitX86(uint32_t Rel, RelocationRef R, uint64_t Value) {
231 251 : switch (Rel) {
232 : case ELF::R_386_NONE:
233 : return 0;
234 250 : case ELF::R_386_32:
235 0 : return Value;
236 0 : case ELF::R_386_PC32:
237 0 : return Value - R.getOffset();
238 : }
239 1 : HasError = true;
240 0 : return 0;
241 : }
242 :
243 : uint64_t visitPPC32(uint32_t Rel, RelocationRef R, uint64_t Value) {
244 0 : if (Rel == ELF::R_PPC_ADDR32)
245 0 : return (Value + getELFAddend(R)) & 0xFFFFFFFF;
246 0 : HasError = true;
247 : return 0;
248 : }
249 :
250 0 : uint64_t visitARM(uint32_t Rel, RelocationRef R, uint64_t Value) {
251 157 : if (Rel == ELF::R_ARM_ABS32) {
252 157 : if ((int64_t)Value < INT32_MIN || (int64_t)Value > UINT32_MAX)
253 0 : HasError = true;
254 0 : return static_cast<uint32_t>(Value);
255 : }
256 0 : HasError = true;
257 0 : return 0;
258 : }
259 :
260 : uint64_t visitLanai(uint32_t Rel, RelocationRef R, uint64_t Value) {
261 0 : if (Rel == ELF::R_LANAI_32)
262 0 : return (Value + getELFAddend(R)) & 0xFFFFFFFF;
263 0 : HasError = true;
264 : return 0;
265 : }
266 :
267 0 : uint64_t visitMips32(uint32_t Rel, RelocationRef R, uint64_t Value) {
268 : // FIXME: Take in account implicit addends to get correct results.
269 94 : if (Rel == ELF::R_MIPS_32)
270 93 : return Value & 0xFFFFFFFF;
271 1 : if (Rel == ELF::R_MIPS_TLS_DTPREL32)
272 1 : return Value & 0xFFFFFFFF;
273 0 : HasError = true;
274 0 : return 0;
275 : }
276 :
277 : uint64_t visitSparc32(uint32_t Rel, RelocationRef R, uint64_t Value) {
278 10 : if (Rel == ELF::R_SPARC_32 || Rel == ELF::R_SPARC_UA32)
279 10 : return Value + getELFAddend(R);
280 0 : HasError = true;
281 : return 0;
282 : }
283 :
284 : uint64_t visitHexagon(uint32_t Rel, RelocationRef R, uint64_t Value) {
285 30 : if (Rel == ELF::R_HEX_32)
286 30 : return Value + getELFAddend(R);
287 0 : HasError = true;
288 : return 0;
289 : }
290 :
291 148 : uint64_t visitCOFF(uint32_t Rel, RelocationRef R, uint64_t Value) {
292 148 : switch (ObjToVisit.getArch()) {
293 58 : case Triple::x86:
294 : switch (Rel) {
295 58 : case COFF::IMAGE_REL_I386_SECREL:
296 : case COFF::IMAGE_REL_I386_DIR32:
297 58 : return static_cast<uint32_t>(Value);
298 : }
299 : break;
300 90 : case Triple::x86_64:
301 : switch (Rel) {
302 73 : case COFF::IMAGE_REL_AMD64_SECREL:
303 73 : return static_cast<uint32_t>(Value);
304 : case COFF::IMAGE_REL_AMD64_ADDR64:
305 : return Value;
306 : }
307 : break;
308 : default:
309 : break;
310 : }
311 0 : HasError = true;
312 0 : return 0;
313 : }
314 :
315 0 : uint64_t visitMachO(uint32_t Rel, RelocationRef R, uint64_t Value) {
316 13 : if (ObjToVisit.getArch() == Triple::x86_64 &&
317 : Rel == MachO::X86_64_RELOC_UNSIGNED)
318 0 : return Value;
319 0 : HasError = true;
320 0 : return 0;
321 : }
322 :
323 0 : uint64_t visitWasm(uint32_t Rel, RelocationRef R, uint64_t Value) {
324 14 : if (ObjToVisit.getArch() == Triple::wasm32) {
325 14 : switch (Rel) {
326 0 : case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
327 : case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
328 : case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
329 : case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
330 : case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
331 : case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
332 : case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
333 : case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
334 : case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
335 : case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
336 : // For wasm section, its offset at 0 -- ignoring Value
337 0 : return 0;
338 : }
339 : }
340 0 : HasError = true;
341 0 : return 0;
342 : }
343 : };
344 :
345 : } // end namespace object
346 : } // end namespace llvm
347 :
348 : #endif // LLVM_OBJECT_RELOCVISITOR_H
|