• 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/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 
28 namespace llvm {
29 namespace object {
30 
31 struct 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;
RelocToApplyRelocToApply38   RelocToApply(int64_t Value, char Width) : Value(Value), Width(Width) {}
RelocToApplyRelocToApply39   RelocToApply() : Value(0), Width(0) {}
40 };
41 
42 /// @brief Base class for object file relocation visitors.
43 class RelocVisitor {
44 public:
RelocVisitor(const ObjectFile & Obj)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 
error()63   bool error() { return HasError; }
64 
65 private:
66   const ObjectFile &ObjToVisit;
67   bool HasError;
68 
visitELF(uint32_t RelocType,RelocationRef R,uint64_t Value)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 
visitCOFF(uint32_t RelocType,RelocationRef R,uint64_t Value)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 
visitMachO(uint32_t RelocType,RelocationRef R,uint64_t Value)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 
getELFAddend(RelocationRef R)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 
getLengthMachO64(RelocationRef R)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
visitELF_386_NONE(RelocationRef R)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.
visitELF_386_32(RelocationRef R,uint64_t Value)270   RelocToApply visitELF_386_32(RelocationRef R, uint64_t Value) {
271     return RelocToApply(Value, 4);
272   }
273 
visitELF_386_PC32(RelocationRef R,uint64_t Value)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
visitELF_X86_64_NONE(RelocationRef R)280   RelocToApply visitELF_X86_64_NONE(RelocationRef R) {
281     return RelocToApply(0, 0);
282   }
visitELF_X86_64_64(RelocationRef R,uint64_t Value)283   RelocToApply visitELF_X86_64_64(RelocationRef R, uint64_t Value) {
284     int64_t Addend = getELFAddend(R);
285     return RelocToApply(Value + Addend, 8);
286   }
visitELF_X86_64_PC32(RelocationRef R,uint64_t Value)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   }
visitELF_X86_64_32(RelocationRef R,uint64_t Value)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   }
visitELF_X86_64_32S(RelocationRef R,uint64_t Value)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
visitELF_PPC64_ADDR32(RelocationRef R,uint64_t Value)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   }
visitELF_PPC64_ADDR64(RelocationRef R,uint64_t Value)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
visitELF_PPC_ADDR32(RelocationRef R,uint64_t Value)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
visitELF_Lanai_32(RelocationRef R,uint64_t Value)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
visitELF_MIPS_32(RelocationRef R,uint64_t Value)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
visitELF_MIPS64_32(RelocationRef R,uint64_t Value)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 
visitELF_MIPS64_64(RelocationRef R,uint64_t Value)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
visitELF_AARCH64_ABS32(RelocationRef R,uint64_t Value)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 
visitELF_AARCH64_ABS64(RelocationRef R,uint64_t Value)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
visitELF_390_32(RelocationRef R,uint64_t Value)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 
visitELF_390_64(RelocationRef R,uint64_t Value)376   RelocToApply visitELF_390_64(RelocationRef R, uint64_t Value) {
377     int64_t Addend = getELFAddend(R);
378     return RelocToApply(Value + Addend, 8);
379   }
380 
visitELF_SPARC_32(RelocationRef R,uint32_t Value)381   RelocToApply visitELF_SPARC_32(RelocationRef R, uint32_t Value) {
382     int32_t Addend = getELFAddend(R);
383     return RelocToApply(Value + Addend, 4);
384   }
385 
visitELF_SPARCV9_32(RelocationRef R,uint64_t Value)386   RelocToApply visitELF_SPARCV9_32(RelocationRef R, uint64_t Value) {
387     int32_t Addend = getELFAddend(R);
388     return RelocToApply(Value + Addend, 4);
389   }
390 
visitELF_SPARCV9_64(RelocationRef R,uint64_t Value)391   RelocToApply visitELF_SPARCV9_64(RelocationRef R, uint64_t Value) {
392     int64_t Addend = getELFAddend(R);
393     return RelocToApply(Value + Addend, 8);
394   }
395 
visitELF_ARM_ABS32(RelocationRef R,uint64_t Value)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
visitCOFF_I386_SECREL(RelocationRef R,uint64_t Value)407   RelocToApply visitCOFF_I386_SECREL(RelocationRef R, uint64_t Value) {
408     return RelocToApply(static_cast<uint32_t>(Value), /*Width=*/4);
409   }
410 
visitCOFF_I386_DIR32(RelocationRef R,uint64_t Value)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
visitCOFF_AMD64_SECREL(RelocationRef R,uint64_t Value)416   RelocToApply visitCOFF_AMD64_SECREL(RelocationRef R, uint64_t Value) {
417     return RelocToApply(static_cast<uint32_t>(Value), /*Width=*/4);
418   }
419 
visitCOFF_AMD64_ADDR64(RelocationRef R,uint64_t Value)420   RelocToApply visitCOFF_AMD64_ADDR64(RelocationRef R, uint64_t Value) {
421     return RelocToApply(Value, /*Width=*/8);
422   }
423 
424   // X86_64 MachO
visitMACHO_X86_64_UNSIGNED(RelocationRef R,uint64_t Value)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