1 //===- RelocVisitor.h - Visitor for object file relocations -----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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"
29 #include <system_error>
34 /// Base class for object file relocation visitors.
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
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
);
56 bool error() { return HasError
; }
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()) {
66 return visitX86_64(Rel
, R
, Value
);
68 case Triple::aarch64_be
:
69 return visitAarch64(Rel
, R
, Value
);
72 return visitBpf(Rel
, R
, Value
);
73 case Triple::mips64el
:
75 return visitMips64(Rel
, R
, Value
);
78 return visitPPC64(Rel
, R
, Value
);
80 return visitSystemz(Rel
, R
, Value
);
82 return visitSparc64(Rel
, R
, Value
);
84 return visitAmdgpu(Rel
, R
, Value
);
92 assert(ObjToVisit
.getBytesInAddress() == 4 &&
93 "Invalid word size in object file");
95 switch (ObjToVisit
.getArch()) {
97 return visitX86(Rel
, R
, Value
);
99 return visitPPC32(Rel
, R
, Value
);
102 return visitARM(Rel
, R
, Value
);
104 return visitAVR(Rel
, R
, Value
);
106 return visitLanai(Rel
, R
, Value
);
109 return visitMips32(Rel
, R
, Value
);
111 return visitSparc32(Rel
, R
, Value
);
112 case Triple::hexagon
:
113 return visitHexagon(Rel
, R
, Value
);
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());
128 uint64_t visitX86_64(uint32_t Rel
, RelocationRef R
, uint64_t Value
) {
130 case ELF::R_X86_64_NONE
:
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;
146 uint64_t visitAarch64(uint32_t Rel
, RelocationRef R
, uint64_t Value
) {
148 case ELF::R_AARCH64_ABS32
: {
149 int64_t Res
= Value
+ getELFAddend(R
);
150 if (Res
< INT32_MIN
|| Res
> UINT32_MAX
)
152 return static_cast<uint32_t>(Res
);
154 case ELF::R_AARCH64_ABS64
:
155 return Value
+ getELFAddend(R
);
161 uint64_t visitBpf(uint32_t Rel
, RelocationRef R
, uint64_t Value
) {
163 case ELF::R_BPF_64_32
:
164 return Value
& 0xFFFFFFFF;
165 case ELF::R_BPF_64_64
:
172 uint64_t visitMips64(uint32_t Rel
, RelocationRef R
, uint64_t Value
) {
175 return (Value
+ getELFAddend(R
)) & 0xFFFFFFFF;
177 return Value
+ getELFAddend(R
);
178 case ELF::R_MIPS_TLS_DTPREL64
:
179 return Value
+ getELFAddend(R
) - 0x8000;
185 uint64_t visitPPC64(uint32_t Rel
, RelocationRef R
, uint64_t Value
) {
187 case ELF::R_PPC64_ADDR32
:
188 return (Value
+ getELFAddend(R
)) & 0xFFFFFFFF;
189 case ELF::R_PPC64_ADDR64
:
190 return Value
+ getELFAddend(R
);
196 uint64_t visitSystemz(uint32_t Rel
, RelocationRef R
, uint64_t Value
) {
198 case ELF::R_390_32
: {
199 int64_t Res
= Value
+ getELFAddend(R
);
200 if (Res
< INT32_MIN
|| Res
> UINT32_MAX
)
202 return static_cast<uint32_t>(Res
);
205 return Value
+ getELFAddend(R
);
211 uint64_t visitSparc64(uint32_t Rel
, RelocationRef R
, uint64_t Value
) {
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
);
223 uint64_t visitAmdgpu(uint32_t Rel
, RelocationRef R
, uint64_t Value
) {
225 case ELF::R_AMDGPU_ABS32
:
226 case ELF::R_AMDGPU_ABS64
:
227 return Value
+ getELFAddend(R
);
233 uint64_t visitX86(uint32_t Rel
, RelocationRef R
, uint64_t Value
) {
235 case ELF::R_386_NONE
:
239 case ELF::R_386_PC32
:
240 return Value
- R
.getOffset();
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;
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
)
257 return static_cast<uint32_t>(Value
);
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;
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;
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;
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
);
297 uint64_t visitHexagon(uint32_t Rel
, RelocationRef R
, uint64_t Value
) {
298 if (Rel
== ELF::R_HEX_32
)
299 return Value
+ getELFAddend(R
);
304 uint64_t visitCOFF(uint32_t Rel
, RelocationRef R
, uint64_t Value
) {
305 switch (ObjToVisit
.getArch()) {
308 case COFF::IMAGE_REL_I386_SECREL
:
309 case COFF::IMAGE_REL_I386_DIR32
:
310 return static_cast<uint32_t>(Value
);
315 case COFF::IMAGE_REL_AMD64_SECREL
:
316 return static_cast<uint32_t>(Value
);
317 case COFF::IMAGE_REL_AMD64_ADDR64
:
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
)
336 uint64_t visitWasm(uint32_t Rel
, RelocationRef R
, uint64_t Value
) {
337 if (ObjToVisit
.getArch() == Triple::wasm32
) {
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
359 } // end namespace object
360 } // end namespace llvm
362 #endif // LLVM_OBJECT_RELOCVISITOR_H