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/Object/COFF.h"
20#include "llvm/Object/ELFObjectFile.h"
21#include "llvm/Object/MachO.h"
22#include "llvm/Object/ObjectFile.h"
23#include "llvm/Support/Debug.h"
24#include "llvm/Support/ELF.h"
25#include "llvm/Support/MachO.h"
26#include "llvm/Support/raw_ostream.h"
27
28namespace llvm {
29namespace object {
30
31struct RelocToApply {
32  // The computed value after applying the relevant relocations.
33  int64_t Value;
34
35  // The width of the value; how many bytes to touch when applying the
36  // relocation.
37  char Width;
38  RelocToApply(int64_t Value, char Width) : Value(Value), Width(Width) {}
39  RelocToApply() : Value(0), Width(0) {}
40};
41
42/// @brief Base class for object file relocation visitors.
43class RelocVisitor {
44public:
45  explicit RelocVisitor(const ObjectFile &Obj)
46    : ObjToVisit(Obj), HasError(false) {}
47
48  // TODO: Should handle multiple applied relocations via either passing in the
49  // previously computed value or just count paired relocations as a single
50  // visit.
51  RelocToApply visit(uint32_t RelocType, RelocationRef R, uint64_t Value = 0) {
52    if (isa<ELFObjectFileBase>(ObjToVisit))
53      return visitELF(RelocType, R, Value);
54    if (isa<COFFObjectFile>(ObjToVisit))
55      return visitCOFF(RelocType, R, Value);
56    if (isa<MachOObjectFile>(ObjToVisit))
57      return visitMachO(RelocType, R, Value);
58
59    HasError = true;
60    return RelocToApply();
61  }
62
63  bool error() { return HasError; }
64
65private:
66  const ObjectFile &ObjToVisit;
67  bool HasError;
68
69  RelocToApply visitELF(uint32_t RelocType, RelocationRef R, uint64_t Value) {
70    if (ObjToVisit.getBytesInAddress() == 8) { // 64-bit object file
71      switch (ObjToVisit.getArch()) {
72      case Triple::x86_64:
73        switch (RelocType) {
74        case llvm::ELF::R_X86_64_NONE:
75          return visitELF_X86_64_NONE(R);
76        case llvm::ELF::R_X86_64_64:
77          return visitELF_X86_64_64(R, Value);
78        case llvm::ELF::R_X86_64_PC32:
79          return visitELF_X86_64_PC32(R, Value);
80        case llvm::ELF::R_X86_64_32:
81          return visitELF_X86_64_32(R, Value);
82        case llvm::ELF::R_X86_64_32S:
83          return visitELF_X86_64_32S(R, Value);
84        default:
85          HasError = true;
86          return RelocToApply();
87        }
88      case Triple::aarch64:
89        switch (RelocType) {
90        case llvm::ELF::R_AARCH64_ABS32:
91          return visitELF_AARCH64_ABS32(R, Value);
92        case llvm::ELF::R_AARCH64_ABS64:
93          return visitELF_AARCH64_ABS64(R, Value);
94        default:
95          HasError = true;
96          return RelocToApply();
97        }
98      case Triple::mips64el:
99      case Triple::mips64:
100        switch (RelocType) {
101        case llvm::ELF::R_MIPS_32:
102          return visitELF_MIPS64_32(R, Value);
103        case llvm::ELF::R_MIPS_64:
104          return visitELF_MIPS64_64(R, Value);
105        default:
106          HasError = true;
107          return RelocToApply();
108        }
109      case Triple::ppc64le:
110      case Triple::ppc64:
111        switch (RelocType) {
112        case llvm::ELF::R_PPC64_ADDR32:
113          return visitELF_PPC64_ADDR32(R, Value);
114        case llvm::ELF::R_PPC64_ADDR64:
115          return visitELF_PPC64_ADDR64(R, Value);
116        default:
117          HasError = true;
118          return RelocToApply();
119        }
120      case Triple::systemz:
121        switch (RelocType) {
122        case llvm::ELF::R_390_32:
123          return visitELF_390_32(R, Value);
124        case llvm::ELF::R_390_64:
125          return visitELF_390_64(R, Value);
126        default:
127          HasError = true;
128          return RelocToApply();
129        }
130      case Triple::sparcv9:
131        switch (RelocType) {
132        case llvm::ELF::R_SPARC_32:
133        case llvm::ELF::R_SPARC_UA32:
134          return visitELF_SPARCV9_32(R, Value);
135        case llvm::ELF::R_SPARC_64:
136        case llvm::ELF::R_SPARC_UA64:
137          return visitELF_SPARCV9_64(R, Value);
138        default:
139          HasError = true;
140          return RelocToApply();
141        }
142      default:
143        HasError = true;
144        return RelocToApply();
145      }
146    } else if (ObjToVisit.getBytesInAddress() == 4) { // 32-bit object file
147      switch (ObjToVisit.getArch()) {
148      case Triple::x86:
149        switch (RelocType) {
150        case llvm::ELF::R_386_NONE:
151          return visitELF_386_NONE(R);
152        case llvm::ELF::R_386_32:
153          return visitELF_386_32(R, Value);
154        case llvm::ELF::R_386_PC32:
155          return visitELF_386_PC32(R, Value);
156        default:
157          HasError = true;
158          return RelocToApply();
159        }
160      case Triple::ppc:
161        switch (RelocType) {
162        case llvm::ELF::R_PPC_ADDR32:
163          return visitELF_PPC_ADDR32(R, Value);
164        default:
165          HasError = true;
166          return RelocToApply();
167        }
168      case Triple::arm:
169      case Triple::armeb:
170        switch (RelocType) {
171        default:
172          HasError = true;
173          return RelocToApply();
174        case llvm::ELF::R_ARM_ABS32:
175          return visitELF_ARM_ABS32(R, Value);
176        }
177      case Triple::lanai:
178        switch (RelocType) {
179        case llvm::ELF::R_LANAI_32:
180          return visitELF_Lanai_32(R, Value);
181        default:
182          HasError = true;
183          return RelocToApply();
184        }
185      case Triple::mipsel:
186      case Triple::mips:
187        switch (RelocType) {
188        case llvm::ELF::R_MIPS_32:
189          return visitELF_MIPS_32(R, Value);
190        default:
191          HasError = true;
192          return RelocToApply();
193        }
194      case Triple::sparc:
195        switch (RelocType) {
196        case llvm::ELF::R_SPARC_32:
197        case llvm::ELF::R_SPARC_UA32:
198          return visitELF_SPARC_32(R, Value);
199        default:
200          HasError = true;
201          return RelocToApply();
202        }
203      default:
204        HasError = true;
205        return RelocToApply();
206      }
207    } else {
208      report_fatal_error("Invalid word size in object file");
209    }
210  }
211
212  RelocToApply visitCOFF(uint32_t RelocType, RelocationRef R, uint64_t Value) {
213    switch (ObjToVisit.getArch()) {
214    case Triple::x86:
215      switch (RelocType) {
216      case COFF::IMAGE_REL_I386_SECREL:
217        return visitCOFF_I386_SECREL(R, Value);
218      case COFF::IMAGE_REL_I386_DIR32:
219        return visitCOFF_I386_DIR32(R, Value);
220      }
221      break;
222    case Triple::x86_64:
223      switch (RelocType) {
224      case COFF::IMAGE_REL_AMD64_SECREL:
225        return visitCOFF_AMD64_SECREL(R, Value);
226      case COFF::IMAGE_REL_AMD64_ADDR64:
227        return visitCOFF_AMD64_ADDR64(R, Value);
228      }
229      break;
230    }
231    HasError = true;
232    return RelocToApply();
233  }
234
235  RelocToApply visitMachO(uint32_t RelocType, RelocationRef R, uint64_t Value) {
236    switch (ObjToVisit.getArch()) {
237    default: break;
238    case Triple::x86_64:
239      switch (RelocType) {
240        default: break;
241        case MachO::X86_64_RELOC_UNSIGNED:
242          return visitMACHO_X86_64_UNSIGNED(R, Value);
243      }
244    }
245    HasError = true;
246    return RelocToApply();
247  }
248
249  int64_t getELFAddend(RelocationRef R) {
250    ErrorOr<int64_t> AddendOrErr = ELFRelocationRef(R).getAddend();
251    if (std::error_code EC = AddendOrErr.getError())
252      report_fatal_error(EC.message());
253    return *AddendOrErr;
254  }
255
256  uint8_t getLengthMachO64(RelocationRef R) {
257    const MachOObjectFile *Obj = cast<MachOObjectFile>(R.getObject());
258    return Obj->getRelocationLength(R.getRawDataRefImpl());
259  }
260
261  /// Operations
262
263  /// 386-ELF
264  RelocToApply visitELF_386_NONE(RelocationRef R) {
265    return RelocToApply(0, 0);
266  }
267
268  // Ideally the Addend here will be the addend in the data for
269  // the relocation. It's not actually the case for Rel relocations.
270  RelocToApply visitELF_386_32(RelocationRef R, uint64_t Value) {
271    return RelocToApply(Value, 4);
272  }
273
274  RelocToApply visitELF_386_PC32(RelocationRef R, uint64_t Value) {
275    uint64_t Address = R.getOffset();
276    return RelocToApply(Value - Address, 4);
277  }
278
279  /// X86-64 ELF
280  RelocToApply visitELF_X86_64_NONE(RelocationRef R) {
281    return RelocToApply(0, 0);
282  }
283  RelocToApply visitELF_X86_64_64(RelocationRef R, uint64_t Value) {
284    int64_t Addend = getELFAddend(R);
285    return RelocToApply(Value + Addend, 8);
286  }
287  RelocToApply visitELF_X86_64_PC32(RelocationRef R, uint64_t Value) {
288    int64_t Addend = getELFAddend(R);
289    uint64_t Address = R.getOffset();
290    return RelocToApply(Value + Addend - Address, 4);
291  }
292  RelocToApply visitELF_X86_64_32(RelocationRef R, uint64_t Value) {
293    int64_t Addend = getELFAddend(R);
294    uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
295    return RelocToApply(Res, 4);
296  }
297  RelocToApply visitELF_X86_64_32S(RelocationRef R, uint64_t Value) {
298    int64_t Addend = getELFAddend(R);
299    int32_t Res = (Value + Addend) & 0xFFFFFFFF;
300    return RelocToApply(Res, 4);
301  }
302
303  /// PPC64 ELF
304  RelocToApply visitELF_PPC64_ADDR32(RelocationRef R, uint64_t Value) {
305    int64_t Addend = getELFAddend(R);
306    uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
307    return RelocToApply(Res, 4);
308  }
309  RelocToApply visitELF_PPC64_ADDR64(RelocationRef R, uint64_t Value) {
310    int64_t Addend = getELFAddend(R);
311    return RelocToApply(Value + Addend, 8);
312  }
313
314  /// PPC32 ELF
315  RelocToApply visitELF_PPC_ADDR32(RelocationRef R, uint64_t Value) {
316    int64_t Addend = getELFAddend(R);
317    uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
318    return RelocToApply(Res, 4);
319  }
320
321  /// Lanai ELF
322  RelocToApply visitELF_Lanai_32(RelocationRef R, uint64_t Value) {
323    int64_t Addend = getELFAddend(R);
324    uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
325    return RelocToApply(Res, 4);
326  }
327
328  /// MIPS ELF
329  RelocToApply visitELF_MIPS_32(RelocationRef R, uint64_t Value) {
330    uint32_t Res = Value & 0xFFFFFFFF;
331    return RelocToApply(Res, 4);
332  }
333
334  /// MIPS64 ELF
335  RelocToApply visitELF_MIPS64_32(RelocationRef R, uint64_t Value) {
336    int64_t Addend = getELFAddend(R);
337    uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
338    return RelocToApply(Res, 4);
339  }
340
341  RelocToApply visitELF_MIPS64_64(RelocationRef R, uint64_t Value) {
342    int64_t Addend = getELFAddend(R);
343    uint64_t Res = (Value + Addend);
344    return RelocToApply(Res, 8);
345  }
346
347  // AArch64 ELF
348  RelocToApply visitELF_AARCH64_ABS32(RelocationRef R, uint64_t Value) {
349    int64_t Addend = getELFAddend(R);
350    int64_t Res =  Value + Addend;
351
352    // Overflow check allows for both signed and unsigned interpretation.
353    if (Res < INT32_MIN || Res > UINT32_MAX)
354      HasError = true;
355
356    return RelocToApply(static_cast<uint32_t>(Res), 4);
357  }
358
359  RelocToApply visitELF_AARCH64_ABS64(RelocationRef R, uint64_t Value) {
360    int64_t Addend = getELFAddend(R);
361    return RelocToApply(Value + Addend, 8);
362  }
363
364  // SystemZ ELF
365  RelocToApply visitELF_390_32(RelocationRef R, uint64_t Value) {
366    int64_t Addend = getELFAddend(R);
367    int64_t Res = Value + Addend;
368
369    // Overflow check allows for both signed and unsigned interpretation.
370    if (Res < INT32_MIN || Res > UINT32_MAX)
371      HasError = true;
372
373    return RelocToApply(static_cast<uint32_t>(Res), 4);
374  }
375
376  RelocToApply visitELF_390_64(RelocationRef R, uint64_t Value) {
377    int64_t Addend = getELFAddend(R);
378    return RelocToApply(Value + Addend, 8);
379  }
380
381  RelocToApply visitELF_SPARC_32(RelocationRef R, uint32_t Value) {
382    int32_t Addend = getELFAddend(R);
383    return RelocToApply(Value + Addend, 4);
384  }
385
386  RelocToApply visitELF_SPARCV9_32(RelocationRef R, uint64_t Value) {
387    int32_t Addend = getELFAddend(R);
388    return RelocToApply(Value + Addend, 4);
389  }
390
391  RelocToApply visitELF_SPARCV9_64(RelocationRef R, uint64_t Value) {
392    int64_t Addend = getELFAddend(R);
393    return RelocToApply(Value + Addend, 8);
394  }
395
396  RelocToApply visitELF_ARM_ABS32(RelocationRef R, uint64_t Value) {
397    int64_t Res = Value;
398
399    // Overflow check allows for both signed and unsigned interpretation.
400    if (Res < INT32_MIN || Res > UINT32_MAX)
401      HasError = true;
402
403    return RelocToApply(static_cast<uint32_t>(Res), 4);
404  }
405
406  /// I386 COFF
407  RelocToApply visitCOFF_I386_SECREL(RelocationRef R, uint64_t Value) {
408    return RelocToApply(static_cast<uint32_t>(Value), /*Width=*/4);
409  }
410
411  RelocToApply visitCOFF_I386_DIR32(RelocationRef R, uint64_t Value) {
412    return RelocToApply(static_cast<uint32_t>(Value), /*Width=*/4);
413  }
414
415  /// AMD64 COFF
416  RelocToApply visitCOFF_AMD64_SECREL(RelocationRef R, uint64_t Value) {
417    return RelocToApply(static_cast<uint32_t>(Value), /*Width=*/4);
418  }
419
420  RelocToApply visitCOFF_AMD64_ADDR64(RelocationRef R, uint64_t Value) {
421    return RelocToApply(Value, /*Width=*/8);
422  }
423
424  // X86_64 MachO
425  RelocToApply visitMACHO_X86_64_UNSIGNED(RelocationRef R, uint64_t Value) {
426    uint8_t Length = getLengthMachO64(R);
427    Length = 1<<Length;
428    return RelocToApply(Value, Length);
429  }
430};
431
432}
433}
434#endif
435