• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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"
26 
27 namespace llvm {
28 namespace object {
29 
30 struct RelocToApply {
31   // The computed value after applying the relevant relocations.
32   int64_t Value;
33 
34   // The width of the value; how many bytes to touch when applying the
35   // relocation.
36   char Width;
RelocToApplyRelocToApply37   RelocToApply(int64_t Value, char Width) : Value(Value), Width(Width) {}
RelocToApplyRelocToApply38   RelocToApply() : Value(0), Width(0) {}
39 };
40 
41 /// @brief Base class for object file relocation visitors.
42 class RelocVisitor {
43 public:
RelocVisitor(const ObjectFile & Obj)44   explicit RelocVisitor(const ObjectFile &Obj)
45     : ObjToVisit(Obj), HasError(false) {}
46 
47   // TODO: Should handle multiple applied relocations via either passing in the
48   // previously computed value or just count paired relocations as a single
49   // visit.
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);
55 
56     HasError = true;
57     return RelocToApply();
58   }
59 
error()60   bool error() { return HasError; }
61 
62 private:
63   const ObjectFile &ObjToVisit;
64   bool HasError;
65 
visitELF(uint32_t RelocType,RelocationRef R,uint64_t Value)66   RelocToApply visitELF(uint32_t RelocType, RelocationRef R, uint64_t Value) {
67     if (ObjToVisit.getBytesInAddress() == 8) { // 64-bit object file
68       switch (ObjToVisit.getArch()) {
69       case Triple::x86_64:
70         switch (RelocType) {
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);
81         default:
82           HasError = true;
83           return RelocToApply();
84         }
85       case Triple::aarch64:
86         switch (RelocType) {
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);
91         default:
92           HasError = true;
93           return RelocToApply();
94         }
95       case Triple::mips64el:
96       case Triple::mips64:
97         switch (RelocType) {
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);
102         default:
103           HasError = true;
104           return RelocToApply();
105         }
106       case Triple::ppc64le:
107       case Triple::ppc64:
108         switch (RelocType) {
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);
113         default:
114           HasError = true;
115           return RelocToApply();
116         }
117       case Triple::systemz:
118         switch (RelocType) {
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);
123         default:
124           HasError = true;
125           return RelocToApply();
126         }
127       case Triple::sparcv9:
128         switch (RelocType) {
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);
135         default:
136           HasError = true;
137           return RelocToApply();
138         }
139       default:
140         HasError = true;
141         return RelocToApply();
142       }
143     } else if (ObjToVisit.getBytesInAddress() == 4) { // 32-bit object file
144       switch (ObjToVisit.getArch()) {
145       case Triple::x86:
146         switch (RelocType) {
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);
153         default:
154           HasError = true;
155           return RelocToApply();
156         }
157       case Triple::ppc:
158         switch (RelocType) {
159         case llvm::ELF::R_PPC_ADDR32:
160           return visitELF_PPC_ADDR32(R, Value);
161         default:
162           HasError = true;
163           return RelocToApply();
164         }
165       case Triple::arm:
166       case Triple::armeb:
167         switch (RelocType) {
168         default:
169           HasError = true;
170           return RelocToApply();
171         case llvm::ELF::R_ARM_ABS32:
172           return visitELF_ARM_ABS32(R, Value);
173         }
174       case Triple::mipsel:
175       case Triple::mips:
176         switch (RelocType) {
177         case llvm::ELF::R_MIPS_32:
178           return visitELF_MIPS_32(R, Value);
179         default:
180           HasError = true;
181           return RelocToApply();
182         }
183       case Triple::sparc:
184         switch (RelocType) {
185         case llvm::ELF::R_SPARC_32:
186         case llvm::ELF::R_SPARC_UA32:
187           return visitELF_SPARC_32(R, Value);
188         default:
189           HasError = true;
190           return RelocToApply();
191         }
192       default:
193         HasError = true;
194         return RelocToApply();
195       }
196     } else {
197       report_fatal_error("Invalid word size in object file");
198     }
199   }
200 
visitCOFF(uint32_t RelocType,RelocationRef R,uint64_t Value)201   RelocToApply visitCOFF(uint32_t RelocType, RelocationRef R, uint64_t Value) {
202     switch (ObjToVisit.getArch()) {
203     case Triple::x86:
204       switch (RelocType) {
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);
209       }
210       break;
211     case Triple::x86_64:
212       switch (RelocType) {
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);
217       }
218       break;
219     }
220     HasError = true;
221     return RelocToApply();
222   }
223 
getELFAddend32LE(RelocationRef R)224   int64_t getELFAddend32LE(RelocationRef R) {
225     const ELF32LEObjectFile *Obj = cast<ELF32LEObjectFile>(R.getObjectFile());
226     DataRefImpl DRI = R.getRawDataRefImpl();
227     int64_t Addend;
228     Obj->getRelocationAddend(DRI, Addend);
229     return Addend;
230   }
231 
getELFAddend64LE(RelocationRef R)232   int64_t getELFAddend64LE(RelocationRef R) {
233     const ELF64LEObjectFile *Obj = cast<ELF64LEObjectFile>(R.getObjectFile());
234     DataRefImpl DRI = R.getRawDataRefImpl();
235     int64_t Addend;
236     Obj->getRelocationAddend(DRI, Addend);
237     return Addend;
238   }
239 
getELFAddend32BE(RelocationRef R)240   int64_t getELFAddend32BE(RelocationRef R) {
241     const ELF32BEObjectFile *Obj = cast<ELF32BEObjectFile>(R.getObjectFile());
242     DataRefImpl DRI = R.getRawDataRefImpl();
243     int64_t Addend;
244     Obj->getRelocationAddend(DRI, Addend);
245     return Addend;
246   }
247 
getELFAddend64BE(RelocationRef R)248   int64_t getELFAddend64BE(RelocationRef R) {
249     const ELF64BEObjectFile *Obj = cast<ELF64BEObjectFile>(R.getObjectFile());
250     DataRefImpl DRI = R.getRawDataRefImpl();
251     int64_t Addend;
252     Obj->getRelocationAddend(DRI, Addend);
253     return Addend;
254   }
255   /// Operations
256 
257   /// 386-ELF
visitELF_386_NONE(RelocationRef R)258   RelocToApply visitELF_386_NONE(RelocationRef R) {
259     return RelocToApply(0, 0);
260   }
261 
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.
visitELF_386_32(RelocationRef R,uint64_t Value)264   RelocToApply visitELF_386_32(RelocationRef R, uint64_t Value) {
265     int64_t Addend = getELFAddend32LE(R);
266     return RelocToApply(Value + Addend, 4);
267   }
268 
visitELF_386_PC32(RelocationRef R,uint64_t Value)269   RelocToApply visitELF_386_PC32(RelocationRef R, uint64_t Value) {
270     int64_t Addend = getELFAddend32LE(R);
271     uint64_t Address;
272     R.getOffset(Address);
273     return RelocToApply(Value + Addend - Address, 4);
274   }
275 
276   /// X86-64 ELF
visitELF_X86_64_NONE(RelocationRef R)277   RelocToApply visitELF_X86_64_NONE(RelocationRef R) {
278     return RelocToApply(0, 0);
279   }
visitELF_X86_64_64(RelocationRef R,uint64_t Value)280   RelocToApply visitELF_X86_64_64(RelocationRef R, uint64_t Value) {
281     int64_t Addend = getELFAddend64LE(R);
282     return RelocToApply(Value + Addend, 8);
283   }
visitELF_X86_64_PC32(RelocationRef R,uint64_t Value)284   RelocToApply visitELF_X86_64_PC32(RelocationRef R, uint64_t Value) {
285     int64_t Addend = getELFAddend64LE(R);
286     uint64_t Address;
287     R.getOffset(Address);
288     return RelocToApply(Value + Addend - Address, 4);
289   }
visitELF_X86_64_32(RelocationRef R,uint64_t Value)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);
294   }
visitELF_X86_64_32S(RelocationRef R,uint64_t Value)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);
299   }
300 
301   /// PPC64 ELF
visitELF_PPC64_ADDR32(RelocationRef R,uint64_t Value)302   RelocToApply visitELF_PPC64_ADDR32(RelocationRef R, uint64_t Value) {
303     int64_t Addend;
304     getELFRelocationAddend(R, Addend);
305     uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
306     return RelocToApply(Res, 4);
307   }
visitELF_PPC64_ADDR64(RelocationRef R,uint64_t Value)308   RelocToApply visitELF_PPC64_ADDR64(RelocationRef R, uint64_t Value) {
309     int64_t Addend;
310     getELFRelocationAddend(R, Addend);
311     return RelocToApply(Value + Addend, 8);
312   }
313 
314   /// PPC32 ELF
visitELF_PPC_ADDR32(RelocationRef R,uint64_t Value)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);
319   }
320 
321   /// MIPS ELF
visitELF_MIPS_32(RelocationRef R,uint64_t Value)322   RelocToApply visitELF_MIPS_32(RelocationRef R, uint64_t Value) {
323     int64_t Addend;
324     getELFRelocationAddend(R, Addend);
325     uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
326     return RelocToApply(Res, 4);
327   }
328 
visitELF_MIPS_64(RelocationRef R,uint64_t Value)329   RelocToApply visitELF_MIPS_64(RelocationRef R, uint64_t Value) {
330     int64_t Addend;
331     getELFRelocationAddend(R, Addend);
332     uint64_t Res = (Value + Addend);
333     return RelocToApply(Res, 8);
334   }
335 
336   // AArch64 ELF
visitELF_AARCH64_ABS32(RelocationRef R,uint64_t Value)337   RelocToApply visitELF_AARCH64_ABS32(RelocationRef R, uint64_t Value) {
338     int64_t Addend;
339     getELFRelocationAddend(R, Addend);
340     int64_t Res =  Value + Addend;
341 
342     // Overflow check allows for both signed and unsigned interpretation.
343     if (Res < INT32_MIN || Res > UINT32_MAX)
344       HasError = true;
345 
346     return RelocToApply(static_cast<uint32_t>(Res), 4);
347   }
348 
visitELF_AARCH64_ABS64(RelocationRef R,uint64_t Value)349   RelocToApply visitELF_AARCH64_ABS64(RelocationRef R, uint64_t Value) {
350     int64_t Addend;
351     getELFRelocationAddend(R, Addend);
352     return RelocToApply(Value + Addend, 8);
353   }
354 
355   // SystemZ ELF
visitELF_390_32(RelocationRef R,uint64_t Value)356   RelocToApply visitELF_390_32(RelocationRef R, uint64_t Value) {
357     int64_t Addend = getELFAddend64BE(R);
358     int64_t Res = Value + Addend;
359 
360     // Overflow check allows for both signed and unsigned interpretation.
361     if (Res < INT32_MIN || Res > UINT32_MAX)
362       HasError = true;
363 
364     return RelocToApply(static_cast<uint32_t>(Res), 4);
365   }
366 
visitELF_390_64(RelocationRef R,uint64_t Value)367   RelocToApply visitELF_390_64(RelocationRef R, uint64_t Value) {
368     int64_t Addend = getELFAddend64BE(R);
369     return RelocToApply(Value + Addend, 8);
370   }
371 
visitELF_SPARC_32(RelocationRef R,uint32_t Value)372   RelocToApply visitELF_SPARC_32(RelocationRef R, uint32_t Value) {
373     int32_t Addend = getELFAddend32BE(R);
374     return RelocToApply(Value + Addend, 4);
375   }
376 
visitELF_SPARCV9_32(RelocationRef R,uint64_t Value)377   RelocToApply visitELF_SPARCV9_32(RelocationRef R, uint64_t Value) {
378     int32_t Addend = getELFAddend64BE(R);
379     return RelocToApply(Value + Addend, 4);
380   }
381 
visitELF_SPARCV9_64(RelocationRef R,uint64_t Value)382   RelocToApply visitELF_SPARCV9_64(RelocationRef R, uint64_t Value) {
383     int64_t Addend = getELFAddend64BE(R);
384     return RelocToApply(Value + Addend, 8);
385   }
386 
visitELF_ARM_ABS32(RelocationRef R,uint64_t Value)387   RelocToApply visitELF_ARM_ABS32(RelocationRef R, uint64_t Value) {
388     int64_t Addend;
389     getELFRelocationAddend(R, Addend);
390     int64_t Res = Value + Addend;
391 
392     // Overflow check allows for both signed and unsigned interpretation.
393     if (Res < INT32_MIN || Res > UINT32_MAX)
394       HasError = true;
395 
396     return RelocToApply(static_cast<uint32_t>(Res), 4);
397   }
398 
399   /// I386 COFF
visitCOFF_I386_SECREL(RelocationRef R,uint64_t Value)400   RelocToApply visitCOFF_I386_SECREL(RelocationRef R, uint64_t Value) {
401     return RelocToApply(static_cast<uint32_t>(Value), /*Width=*/4);
402   }
403 
visitCOFF_I386_DIR32(RelocationRef R,uint64_t Value)404   RelocToApply visitCOFF_I386_DIR32(RelocationRef R, uint64_t Value) {
405     return RelocToApply(static_cast<uint32_t>(Value), /*Width=*/4);
406   }
407 
408   /// AMD64 COFF
visitCOFF_AMD64_SECREL(RelocationRef R,uint64_t Value)409   RelocToApply visitCOFF_AMD64_SECREL(RelocationRef R, uint64_t Value) {
410     return RelocToApply(static_cast<uint32_t>(Value), /*Width=*/4);
411   }
412 
visitCOFF_AMD64_ADDR64(RelocationRef R,uint64_t Value)413   RelocToApply visitCOFF_AMD64_ADDR64(RelocationRef R, uint64_t Value) {
414     return RelocToApply(Value, /*Width=*/8);
415   }
416 };
417 
418 }
419 }
420 #endif
421