blob: 76f3fab2febb8471d586c32337ef9f1498867685 [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- RelocVisitor.h - Visitor for object file relocations -----*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// 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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
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.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_OBJECT_RELOCVISITOR_H
16#define LLVM_OBJECT_RELOCVISITOR_H
17
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"
Andrew Scullcdfcccc2018-10-05 20:58:37 +010025#include "llvm/Object/Wasm.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010026#include "llvm/Support/Casting.h"
27#include "llvm/Support/ErrorHandling.h"
28#include <cstdint>
29#include <system_error>
30
31namespace llvm {
32namespace object {
33
Andrew Scullcdfcccc2018-10-05 20:58:37 +010034/// Base class for object file relocation visitors.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010035class RelocVisitor {
36public:
37 explicit RelocVisitor(const ObjectFile &Obj) : ObjToVisit(Obj) {}
38
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);
Andrew Scullcdfcccc2018-10-05 20:58:37 +010049 if (isa<WasmObjectFile>(ObjToVisit))
50 return visitWasm(Rel, R, Value);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010051
52 HasError = true;
53 return 0;
54 }
55
56 bool error() { return HasError; }
57
58private:
59 const ObjectFile &ObjToVisit;
60 bool HasError = false;
61
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;
88 }
89 }
90
91 // 32-bit object file
92 assert(ObjToVisit.getBytesInAddress() == 4 &&
93 "Invalid word size in object file");
94
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);
Andrew Walbran16937d02019-10-22 13:54:20 +0100103 case Triple::avr:
104 return visitAVR(Rel, R, Value);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100105 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;
117 }
118 }
119
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());
124 });
125 return *AddendOrErr;
126 }
127
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:
Andrew Walbran16937d02019-10-22 13:54:20 +0100133 case ELF::R_X86_64_DTPOFF32:
134 case ELF::R_X86_64_DTPOFF64:
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100135 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;
141 }
142 HasError = true;
143 return 0;
144 }
145
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);
153 }
154 case ELF::R_AARCH64_ABS64:
155 return Value + getELFAddend(R);
156 }
157 HasError = true;
158 return 0;
159 }
160
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;
167 }
168 HasError = true;
169 return 0;
170 }
171
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;
180 }
181 HasError = true;
182 return 0;
183 }
184
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);
191 }
192 HasError = true;
193 return 0;
194 }
195
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);
203 }
204 case ELF::R_390_64:
205 return Value + getELFAddend(R);
206 }
207 HasError = true;
208 return 0;
209 }
210
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);
218 }
219 HasError = true;
220 return 0;
221 }
222
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);
228 }
229 HasError = true;
230 return 0;
231 }
232
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();
241 }
242 HasError = true;
243 return 0;
244 }
245
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;
251 }
252
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);
258 }
259 HasError = true;
260 return 0;
261 }
262
Andrew Walbran16937d02019-10-22 13:54:20 +0100263 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;
268 }
269 HasError = true;
270 return 0;
271 }
272
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100273 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;
278 }
279
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;
288 }
289
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;
295 }
296
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;
302 }
303
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);
311 }
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;
319 }
320 break;
321 default:
322 break;
323 }
324 HasError = true;
325 return 0;
326 }
327
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;
334 }
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100335
336 uint64_t visitWasm(uint32_t Rel, RelocationRef R, uint64_t Value) {
337 if (ObjToVisit.getArch() == Triple::wasm32) {
338 switch (Rel) {
Andrew Walbran16937d02019-10-22 13:54:20 +0100339 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:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100350 // For wasm section, its offset at 0 -- ignoring Value
351 return 0;
352 }
353 }
354 HasError = true;
355 return 0;
356 }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100357};
358
359} // end namespace object
360} // end namespace llvm
361
362#endif // LLVM_OBJECT_RELOCVISITOR_H