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/Support/Casting.h"
27#include "llvm/Support/ErrorHandling.h"
28#include "llvm/Support/ErrorOr.h"
29#include <cstdint>
30#include <system_error>
31
32namespace llvm {
33namespace object {
34
35/// @brief Base class for object file relocation visitors.
36class RelocVisitor {
37public:
38  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  uint64_t visit(uint32_t Rel, RelocationRef R, uint64_t Value = 0) {
44    if (isa<ELFObjectFileBase>(ObjToVisit))
45      return visitELF(Rel, R, Value);
46    if (isa<COFFObjectFile>(ObjToVisit))
47      return visitCOFF(Rel, R, Value);
48    if (isa<MachOObjectFile>(ObjToVisit))
49      return visitMachO(Rel, R, Value);
50
51    HasError = true;
52    return 0;
53  }
54
55  bool error() { return HasError; }
56
57private:
58  const ObjectFile &ObjToVisit;
59  bool HasError = false;
60
61  uint64_t visitELF(uint32_t Rel, RelocationRef R, uint64_t Value) {
62    if (ObjToVisit.getBytesInAddress() == 8) { // 64-bit object file
63      switch (ObjToVisit.getArch()) {
64      case Triple::x86_64:
65        return visitX86_64(Rel, R, Value);
66      case Triple::aarch64:
67      case Triple::aarch64_be:
68        return visitAarch64(Rel, R, Value);
69      case Triple::bpfel:
70      case Triple::bpfeb:
71        return visitBpf(Rel, R, Value);
72      case Triple::mips64el:
73      case Triple::mips64:
74        return visitMips64(Rel, R, Value);
75      case Triple::ppc64le:
76      case Triple::ppc64:
77        return visitPPC64(Rel, R, Value);
78      case Triple::systemz:
79        return visitSystemz(Rel, R, Value);
80      case Triple::sparcv9:
81        return visitSparc64(Rel, R, Value);
82      case Triple::amdgcn:
83        return visitAmdgpu(Rel, R, Value);
84      default:
85        HasError = true;
86        return 0;
87      }
88    }
89
90    // 32-bit object file
91    assert(ObjToVisit.getBytesInAddress() == 4 &&
92           "Invalid word size in object file");
93
94    switch (ObjToVisit.getArch()) {
95    case Triple::x86:
96      return visitX86(Rel, R, Value);
97    case Triple::ppc:
98      return visitPPC32(Rel, R, Value);
99    case Triple::arm:
100    case Triple::armeb:
101      return visitARM(Rel, R, Value);
102    case Triple::lanai:
103      return visitLanai(Rel, R, Value);
104    case Triple::mipsel:
105    case Triple::mips:
106      return visitMips32(Rel, R, Value);
107    case Triple::sparc:
108      return visitSparc32(Rel, R, Value);
109    case Triple::hexagon:
110      return visitHexagon(Rel, R, Value);
111    default:
112      HasError = true;
113      return 0;
114    }
115  }
116
117  int64_t getELFAddend(RelocationRef R) {
118    ErrorOr<int64_t> AddendOrErr = ELFRelocationRef(R).getAddend();
119    if (std::error_code EC = AddendOrErr.getError())
120      report_fatal_error(EC.message());
121    return *AddendOrErr;
122  }
123
124  uint64_t visitX86_64(uint32_t Rel, RelocationRef R, uint64_t Value) {
125    switch (Rel) {
126    case ELF::R_X86_64_NONE:
127      return 0;
128    case ELF::R_X86_64_64:
129      return Value + getELFAddend(R);
130    case ELF::R_X86_64_PC32:
131      return Value + getELFAddend(R) - R.getOffset();
132    case ELF::R_X86_64_32:
133    case ELF::R_X86_64_32S:
134      return (Value + getELFAddend(R)) & 0xFFFFFFFF;
135    }
136    HasError = true;
137    return 0;
138  }
139
140  uint64_t visitAarch64(uint32_t Rel, RelocationRef R, uint64_t Value) {
141    switch (Rel) {
142    case ELF::R_AARCH64_ABS32: {
143      int64_t Res = Value + getELFAddend(R);
144      if (Res < INT32_MIN || Res > UINT32_MAX)
145        HasError = true;
146      return static_cast<uint32_t>(Res);
147    }
148    case ELF::R_AARCH64_ABS64:
149      return Value + getELFAddend(R);
150    }
151    HasError = true;
152    return 0;
153  }
154
155  uint64_t visitBpf(uint32_t Rel, RelocationRef R, uint64_t Value) {
156    switch (Rel) {
157    case ELF::R_BPF_64_32:
158      return Value & 0xFFFFFFFF;
159    case ELF::R_BPF_64_64:
160      return Value;
161    }
162    HasError = true;
163    return 0;
164  }
165
166  uint64_t visitMips64(uint32_t Rel, RelocationRef R, uint64_t Value) {
167    switch (Rel) {
168    case ELF::R_MIPS_32:
169      return (Value + getELFAddend(R)) & 0xFFFFFFFF;
170    case ELF::R_MIPS_64:
171      return Value + getELFAddend(R);
172    }
173    HasError = true;
174    return 0;
175  }
176
177  uint64_t visitPPC64(uint32_t Rel, RelocationRef R, uint64_t Value) {
178    switch (Rel) {
179    case ELF::R_PPC64_ADDR32:
180      return (Value + getELFAddend(R)) & 0xFFFFFFFF;
181    case ELF::R_PPC64_ADDR64:
182      return Value + getELFAddend(R);
183    }
184    HasError = true;
185    return 0;
186  }
187
188  uint64_t visitSystemz(uint32_t Rel, RelocationRef R, uint64_t Value) {
189    switch (Rel) {
190    case ELF::R_390_32: {
191      int64_t Res = Value + getELFAddend(R);
192      if (Res < INT32_MIN || Res > UINT32_MAX)
193        HasError = true;
194      return static_cast<uint32_t>(Res);
195    }
196    case ELF::R_390_64:
197      return Value + getELFAddend(R);
198    }
199    HasError = true;
200    return 0;
201  }
202
203  uint64_t visitSparc64(uint32_t Rel, RelocationRef R, uint64_t Value) {
204    switch (Rel) {
205    case ELF::R_SPARC_32:
206    case ELF::R_SPARC_64:
207    case ELF::R_SPARC_UA32:
208    case ELF::R_SPARC_UA64:
209      return Value + getELFAddend(R);
210    }
211    HasError = true;
212    return 0;
213  }
214
215  uint64_t visitAmdgpu(uint32_t Rel, RelocationRef R, uint64_t Value) {
216    switch (Rel) {
217    case ELF::R_AMDGPU_ABS32:
218    case ELF::R_AMDGPU_ABS64:
219      return Value + getELFAddend(R);
220    }
221    HasError = true;
222    return 0;
223  }
224
225  uint64_t visitX86(uint32_t Rel, RelocationRef R, uint64_t Value) {
226    switch (Rel) {
227    case ELF::R_386_NONE:
228      return 0;
229    case ELF::R_386_32:
230      return Value;
231    case ELF::R_386_PC32:
232      return Value - R.getOffset();
233    }
234    HasError = true;
235    return 0;
236  }
237
238  uint64_t visitPPC32(uint32_t Rel, RelocationRef R, uint64_t Value) {
239    if (Rel == ELF::R_PPC_ADDR32)
240      return (Value + getELFAddend(R)) & 0xFFFFFFFF;
241    HasError = true;
242    return 0;
243  }
244
245  uint64_t visitARM(uint32_t Rel, RelocationRef R, uint64_t Value) {
246    if (Rel == ELF::R_ARM_ABS32) {
247      if ((int64_t)Value < INT32_MIN || (int64_t)Value > UINT32_MAX)
248        HasError = true;
249      return static_cast<uint32_t>(Value);
250    }
251    HasError = true;
252    return 0;
253  }
254
255  uint64_t visitLanai(uint32_t Rel, RelocationRef R, uint64_t Value) {
256    if (Rel == ELF::R_LANAI_32)
257      return (Value + getELFAddend(R)) & 0xFFFFFFFF;
258    HasError = true;
259    return 0;
260  }
261
262  uint64_t visitMips32(uint32_t Rel, RelocationRef R, uint64_t Value) {
263    if (Rel == ELF::R_MIPS_32)
264      return Value & 0xFFFFFFFF;
265    HasError = true;
266    return 0;
267  }
268
269  uint64_t visitSparc32(uint32_t Rel, RelocationRef R, uint64_t Value) {
270    if (Rel == ELF::R_SPARC_32 || Rel == ELF::R_SPARC_UA32)
271      return Value + getELFAddend(R);
272    HasError = true;
273    return 0;
274  }
275
276  uint64_t visitHexagon(uint32_t Rel, RelocationRef R, uint64_t Value) {
277    if (Rel == ELF::R_HEX_32)
278      return Value + getELFAddend(R);
279    HasError = true;
280    return 0;
281  }
282
283  uint64_t visitCOFF(uint32_t Rel, RelocationRef R, uint64_t Value) {
284    switch (ObjToVisit.getArch()) {
285    case Triple::x86:
286      switch (Rel) {
287      case COFF::IMAGE_REL_I386_SECREL:
288      case COFF::IMAGE_REL_I386_DIR32:
289        return static_cast<uint32_t>(Value);
290      }
291      break;
292    case Triple::x86_64:
293      switch (Rel) {
294      case COFF::IMAGE_REL_AMD64_SECREL:
295        return static_cast<uint32_t>(Value);
296      case COFF::IMAGE_REL_AMD64_ADDR64:
297        return Value;
298      }
299      break;
300    }
301    HasError = true;
302    return 0;
303  }
304
305  uint64_t visitMachO(uint32_t Rel, RelocationRef R, uint64_t Value) {
306    if (ObjToVisit.getArch() == Triple::x86_64 &&
307        Rel == MachO::X86_64_RELOC_UNSIGNED)
308      return Value;
309    HasError = true;
310    return 0;
311  }
312};
313
314} // end namespace object
315} // end namespace llvm
316
317#endif // LLVM_OBJECT_RELOCVISITOR_H
318