1 //===-- RelocVisitor.h - Visitor for object file relocations -*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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.
14 //===----------------------------------------------------------------------===//
16 #ifndef LLVM_OBJECT_RELOCVISITOR_H
17 #define LLVM_OBJECT_RELOCVISITOR_H
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Object/COFF.h"
21 #include "llvm/Object/ELFObjectFile.h"
22 #include "llvm/Object/ObjectFile.h"
23 #include "llvm/Support/Debug.h"
24 #include "llvm/Support/ELF.h"
25 #include "llvm/Support/raw_ostream.h"
31 // The computed value after applying the relevant relocations.
34 // The width of the value; how many bytes to touch when applying the
37 RelocToApply(int64_t Value, char Width) : Value(Value), Width(Width) {}
38 RelocToApply() : Value(0), Width(0) {}
41 /// @brief Base class for object file relocation visitors.
44 explicit RelocVisitor(const ObjectFile &Obj)
45 : ObjToVisit(Obj), HasError(false) {}
47 // TODO: Should handle multiple applied relocations via either passing in the
48 // previously computed value or just count paired relocations as a single
50 RelocToApply visit(uint32_t RelocType, RelocationRef R, uint64_t Value = 0) {
51 if (isa<ELFObjectFileBase>(ObjToVisit))
52 return visitELF(RelocType, R, Value);
53 if (isa<COFFObjectFile>(ObjToVisit))
54 return visitCOFF(RelocType, R, Value);
57 return RelocToApply();
60 bool error() { return HasError; }
63 const ObjectFile &ObjToVisit;
66 RelocToApply visitELF(uint32_t RelocType, RelocationRef R, uint64_t Value) {
67 if (ObjToVisit.getBytesInAddress() == 8) { // 64-bit object file
68 switch (ObjToVisit.getArch()) {
71 case llvm::ELF::R_X86_64_NONE:
72 return visitELF_X86_64_NONE(R);
73 case llvm::ELF::R_X86_64_64:
74 return visitELF_X86_64_64(R, Value);
75 case llvm::ELF::R_X86_64_PC32:
76 return visitELF_X86_64_PC32(R, Value);
77 case llvm::ELF::R_X86_64_32:
78 return visitELF_X86_64_32(R, Value);
79 case llvm::ELF::R_X86_64_32S:
80 return visitELF_X86_64_32S(R, Value);
83 return RelocToApply();
87 case llvm::ELF::R_AARCH64_ABS32:
88 return visitELF_AARCH64_ABS32(R, Value);
89 case llvm::ELF::R_AARCH64_ABS64:
90 return visitELF_AARCH64_ABS64(R, Value);
93 return RelocToApply();
95 case Triple::mips64el:
98 case llvm::ELF::R_MIPS_32:
99 return visitELF_MIPS_32(R, Value);
100 case llvm::ELF::R_MIPS_64:
101 return visitELF_MIPS_64(R, Value);
104 return RelocToApply();
106 case Triple::ppc64le:
109 case llvm::ELF::R_PPC64_ADDR32:
110 return visitELF_PPC64_ADDR32(R, Value);
111 case llvm::ELF::R_PPC64_ADDR64:
112 return visitELF_PPC64_ADDR64(R, Value);
115 return RelocToApply();
117 case Triple::systemz:
119 case llvm::ELF::R_390_32:
120 return visitELF_390_32(R, Value);
121 case llvm::ELF::R_390_64:
122 return visitELF_390_64(R, Value);
125 return RelocToApply();
127 case Triple::sparcv9:
129 case llvm::ELF::R_SPARC_32:
130 case llvm::ELF::R_SPARC_UA32:
131 return visitELF_SPARCV9_32(R, Value);
132 case llvm::ELF::R_SPARC_64:
133 case llvm::ELF::R_SPARC_UA64:
134 return visitELF_SPARCV9_64(R, Value);
137 return RelocToApply();
141 return RelocToApply();
143 } else if (ObjToVisit.getBytesInAddress() == 4) { // 32-bit object file
144 switch (ObjToVisit.getArch()) {
147 case llvm::ELF::R_386_NONE:
148 return visitELF_386_NONE(R);
149 case llvm::ELF::R_386_32:
150 return visitELF_386_32(R, Value);
151 case llvm::ELF::R_386_PC32:
152 return visitELF_386_PC32(R, Value);
155 return RelocToApply();
159 case llvm::ELF::R_PPC_ADDR32:
160 return visitELF_PPC_ADDR32(R, Value);
163 return RelocToApply();
170 return RelocToApply();
171 case llvm::ELF::R_ARM_ABS32:
172 return visitELF_ARM_ABS32(R, Value);
177 case llvm::ELF::R_MIPS_32:
178 return visitELF_MIPS_32(R, Value);
181 return RelocToApply();
185 case llvm::ELF::R_SPARC_32:
186 case llvm::ELF::R_SPARC_UA32:
187 return visitELF_SPARC_32(R, Value);
190 return RelocToApply();
194 return RelocToApply();
197 report_fatal_error("Invalid word size in object file");
201 RelocToApply visitCOFF(uint32_t RelocType, RelocationRef R, uint64_t Value) {
202 switch (ObjToVisit.getArch()) {
205 case COFF::IMAGE_REL_I386_SECREL:
206 return visitCOFF_I386_SECREL(R, Value);
207 case COFF::IMAGE_REL_I386_DIR32:
208 return visitCOFF_I386_DIR32(R, Value);
213 case COFF::IMAGE_REL_AMD64_SECREL:
214 return visitCOFF_AMD64_SECREL(R, Value);
215 case COFF::IMAGE_REL_AMD64_ADDR64:
216 return visitCOFF_AMD64_ADDR64(R, Value);
221 return RelocToApply();
224 int64_t getELFAddend32LE(RelocationRef R) {
225 const ELF32LEObjectFile *Obj = cast<ELF32LEObjectFile>(R.getObjectFile());
226 DataRefImpl DRI = R.getRawDataRefImpl();
228 Obj->getRelocationAddend(DRI, Addend);
232 int64_t getELFAddend64LE(RelocationRef R) {
233 const ELF64LEObjectFile *Obj = cast<ELF64LEObjectFile>(R.getObjectFile());
234 DataRefImpl DRI = R.getRawDataRefImpl();
236 Obj->getRelocationAddend(DRI, Addend);
240 int64_t getELFAddend32BE(RelocationRef R) {
241 const ELF32BEObjectFile *Obj = cast<ELF32BEObjectFile>(R.getObjectFile());
242 DataRefImpl DRI = R.getRawDataRefImpl();
244 Obj->getRelocationAddend(DRI, Addend);
248 int64_t getELFAddend64BE(RelocationRef R) {
249 const ELF64BEObjectFile *Obj = cast<ELF64BEObjectFile>(R.getObjectFile());
250 DataRefImpl DRI = R.getRawDataRefImpl();
252 Obj->getRelocationAddend(DRI, Addend);
258 RelocToApply visitELF_386_NONE(RelocationRef R) {
259 return RelocToApply(0, 0);
262 // Ideally the Addend here will be the addend in the data for
263 // the relocation. It's not actually the case for Rel relocations.
264 RelocToApply visitELF_386_32(RelocationRef R, uint64_t Value) {
265 int64_t Addend = getELFAddend32LE(R);
266 return RelocToApply(Value + Addend, 4);
269 RelocToApply visitELF_386_PC32(RelocationRef R, uint64_t Value) {
270 int64_t Addend = getELFAddend32LE(R);
272 R.getOffset(Address);
273 return RelocToApply(Value + Addend - Address, 4);
277 RelocToApply visitELF_X86_64_NONE(RelocationRef R) {
278 return RelocToApply(0, 0);
280 RelocToApply visitELF_X86_64_64(RelocationRef R, uint64_t Value) {
281 int64_t Addend = getELFAddend64LE(R);
282 return RelocToApply(Value + Addend, 8);
284 RelocToApply visitELF_X86_64_PC32(RelocationRef R, uint64_t Value) {
285 int64_t Addend = getELFAddend64LE(R);
287 R.getOffset(Address);
288 return RelocToApply(Value + Addend - Address, 4);
290 RelocToApply visitELF_X86_64_32(RelocationRef R, uint64_t Value) {
291 int64_t Addend = getELFAddend64LE(R);
292 uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
293 return RelocToApply(Res, 4);
295 RelocToApply visitELF_X86_64_32S(RelocationRef R, uint64_t Value) {
296 int64_t Addend = getELFAddend64LE(R);
297 int32_t Res = (Value + Addend) & 0xFFFFFFFF;
298 return RelocToApply(Res, 4);
302 RelocToApply visitELF_PPC64_ADDR32(RelocationRef R, uint64_t Value) {
304 getELFRelocationAddend(R, Addend);
305 uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
306 return RelocToApply(Res, 4);
308 RelocToApply visitELF_PPC64_ADDR64(RelocationRef R, uint64_t Value) {
310 getELFRelocationAddend(R, Addend);
311 return RelocToApply(Value + Addend, 8);
315 RelocToApply visitELF_PPC_ADDR32(RelocationRef R, uint64_t Value) {
316 int64_t Addend = getELFAddend32BE(R);
317 uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
318 return RelocToApply(Res, 4);
322 RelocToApply visitELF_MIPS_32(RelocationRef R, uint64_t Value) {
324 getELFRelocationAddend(R, Addend);
325 uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
326 return RelocToApply(Res, 4);
329 RelocToApply visitELF_MIPS_64(RelocationRef R, uint64_t Value) {
331 getELFRelocationAddend(R, Addend);
332 uint64_t Res = (Value + Addend);
333 return RelocToApply(Res, 8);
337 RelocToApply visitELF_AARCH64_ABS32(RelocationRef R, uint64_t Value) {
339 getELFRelocationAddend(R, Addend);
340 int64_t Res = Value + Addend;
342 // Overflow check allows for both signed and unsigned interpretation.
343 if (Res < INT32_MIN || Res > UINT32_MAX)
346 return RelocToApply(static_cast<uint32_t>(Res), 4);
349 RelocToApply visitELF_AARCH64_ABS64(RelocationRef R, uint64_t Value) {
351 getELFRelocationAddend(R, Addend);
352 return RelocToApply(Value + Addend, 8);
356 RelocToApply visitELF_390_32(RelocationRef R, uint64_t Value) {
357 int64_t Addend = getELFAddend64BE(R);
358 int64_t Res = Value + Addend;
360 // Overflow check allows for both signed and unsigned interpretation.
361 if (Res < INT32_MIN || Res > UINT32_MAX)
364 return RelocToApply(static_cast<uint32_t>(Res), 4);
367 RelocToApply visitELF_390_64(RelocationRef R, uint64_t Value) {
368 int64_t Addend = getELFAddend64BE(R);
369 return RelocToApply(Value + Addend, 8);
372 RelocToApply visitELF_SPARC_32(RelocationRef R, uint32_t Value) {
373 int32_t Addend = getELFAddend32BE(R);
374 return RelocToApply(Value + Addend, 4);
377 RelocToApply visitELF_SPARCV9_32(RelocationRef R, uint64_t Value) {
378 int32_t Addend = getELFAddend64BE(R);
379 return RelocToApply(Value + Addend, 4);
382 RelocToApply visitELF_SPARCV9_64(RelocationRef R, uint64_t Value) {
383 int64_t Addend = getELFAddend64BE(R);
384 return RelocToApply(Value + Addend, 8);
387 RelocToApply visitELF_ARM_ABS32(RelocationRef R, uint64_t Value) {
389 getELFRelocationAddend(R, Addend);
390 int64_t Res = Value + Addend;
392 // Overflow check allows for both signed and unsigned interpretation.
393 if (Res < INT32_MIN || Res > UINT32_MAX)
396 return RelocToApply(static_cast<uint32_t>(Res), 4);
400 RelocToApply visitCOFF_I386_SECREL(RelocationRef R, uint64_t Value) {
401 return RelocToApply(static_cast<uint32_t>(Value), /*Width=*/4);
404 RelocToApply visitCOFF_I386_DIR32(RelocationRef R, uint64_t Value) {
405 return RelocToApply(static_cast<uint32_t>(Value), /*Width=*/4);
409 RelocToApply visitCOFF_AMD64_SECREL(RelocationRef R, uint64_t Value) {
410 return RelocToApply(static_cast<uint32_t>(Value), /*Width=*/4);
413 RelocToApply visitCOFF_AMD64_ADDR64(RelocationRef R, uint64_t Value) {
414 return RelocToApply(Value, /*Width=*/8);