Home | History | Annotate | Download | only in Object
      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/ELFObjectFile.h"
     21 #include "llvm/Object/ObjectFile.h"
     22 #include "llvm/Support/Debug.h"
     23 #include "llvm/Support/ELF.h"
     24 #include "llvm/Support/raw_ostream.h"
     25 
     26 namespace llvm {
     27 namespace object {
     28 
     29 struct RelocToApply {
     30   // The computed value after applying the relevant relocations.
     31   int64_t Value;
     32 
     33   // The width of the value; how many bytes to touch when applying the
     34   // relocation.
     35   char Width;
     36   RelocToApply(int64_t Value, char Width) : Value(Value), Width(Width) {}
     37   RelocToApply() : Value(0), Width(0) {}
     38 };
     39 
     40 /// @brief Base class for object file relocation visitors.
     41 class RelocVisitor {
     42 public:
     43   explicit RelocVisitor(StringRef FileFormat)
     44     : FileFormat(FileFormat), HasError(false) {}
     45 
     46   // TODO: Should handle multiple applied relocations via either passing in the
     47   // previously computed value or just count paired relocations as a single
     48   // visit.
     49   RelocToApply visit(uint32_t RelocType, RelocationRef R, uint64_t SecAddr = 0,
     50                      uint64_t Value = 0) {
     51     if (FileFormat == "ELF64-x86-64") {
     52       switch (RelocType) {
     53         case llvm::ELF::R_X86_64_NONE:
     54           return visitELF_X86_64_NONE(R);
     55         case llvm::ELF::R_X86_64_64:
     56           return visitELF_X86_64_64(R, Value);
     57         case llvm::ELF::R_X86_64_PC32:
     58           return visitELF_X86_64_PC32(R, Value, SecAddr);
     59         case llvm::ELF::R_X86_64_32:
     60           return visitELF_X86_64_32(R, Value);
     61         case llvm::ELF::R_X86_64_32S:
     62           return visitELF_X86_64_32S(R, Value);
     63         default:
     64           HasError = true;
     65           return RelocToApply();
     66       }
     67     } else if (FileFormat == "ELF32-i386") {
     68       switch (RelocType) {
     69       case llvm::ELF::R_386_NONE:
     70         return visitELF_386_NONE(R);
     71       case llvm::ELF::R_386_32:
     72         return visitELF_386_32(R, Value);
     73       case llvm::ELF::R_386_PC32:
     74         return visitELF_386_PC32(R, Value, SecAddr);
     75       default:
     76         HasError = true;
     77         return RelocToApply();
     78       }
     79     } else if (FileFormat == "ELF64-ppc64") {
     80       switch (RelocType) {
     81       case llvm::ELF::R_PPC64_ADDR32:
     82         return visitELF_PPC64_ADDR32(R, Value);
     83       case llvm::ELF::R_PPC64_ADDR64:
     84         return visitELF_PPC64_ADDR64(R, Value);
     85       default:
     86         HasError = true;
     87         return RelocToApply();
     88       }
     89     } else if (FileFormat == "ELF32-ppc") {
     90       switch (RelocType) {
     91       case llvm::ELF::R_PPC_ADDR32:
     92         return visitELF_PPC_ADDR32(R, Value);
     93       default:
     94         HasError = true;
     95         return RelocToApply();
     96       }
     97     } else if (FileFormat == "ELF32-mips") {
     98       switch (RelocType) {
     99       case llvm::ELF::R_MIPS_32:
    100         return visitELF_MIPS_32(R, Value);
    101       default:
    102         HasError = true;
    103         return RelocToApply();
    104       }
    105     } else if (FileFormat == "ELF64-mips") {
    106       switch (RelocType) {
    107       case llvm::ELF::R_MIPS_32:
    108         return visitELF_MIPS_32(R, Value);
    109       case llvm::ELF::R_MIPS_64:
    110         return visitELF_MIPS_64(R, Value);
    111       default:
    112         HasError = true;
    113         return RelocToApply();
    114       }
    115     } else if (FileFormat == "ELF64-aarch64") {
    116       switch (RelocType) {
    117       case llvm::ELF::R_AARCH64_ABS32:
    118         return visitELF_AARCH64_ABS32(R, Value);
    119       case llvm::ELF::R_AARCH64_ABS64:
    120         return visitELF_AARCH64_ABS64(R, Value);
    121       default:
    122         HasError = true;
    123         return RelocToApply();
    124       }
    125     } else if (FileFormat == "ELF64-s390") {
    126       switch (RelocType) {
    127       case llvm::ELF::R_390_32:
    128         return visitELF_390_32(R, Value);
    129       case llvm::ELF::R_390_64:
    130         return visitELF_390_64(R, Value);
    131       default:
    132         HasError = true;
    133         return RelocToApply();
    134       }
    135     } else if (FileFormat == "ELF32-sparc") {
    136       switch (RelocType) {
    137       case llvm::ELF::R_SPARC_32:
    138       case llvm::ELF::R_SPARC_UA32:
    139         return visitELF_SPARC_32(R, Value);
    140       default:
    141         HasError = true;
    142         return RelocToApply();
    143       }
    144     } else if (FileFormat == "ELF64-sparc") {
    145       switch (RelocType) {
    146       case llvm::ELF::R_SPARC_32:
    147       case llvm::ELF::R_SPARC_UA32:
    148         return visitELF_SPARCV9_32(R, Value);
    149       case llvm::ELF::R_SPARC_64:
    150       case llvm::ELF::R_SPARC_UA64:
    151         return visitELF_SPARCV9_64(R, Value);
    152       default:
    153         HasError = true;
    154         return RelocToApply();
    155       }
    156     } else if (FileFormat == "ELF32-arm") {
    157       switch (RelocType) {
    158       default:
    159         HasError = true;
    160         return RelocToApply();
    161       case llvm::ELF::R_ARM_ABS32:
    162         return visitELF_ARM_ABS32(R, Value);
    163       }
    164     }
    165     HasError = true;
    166     return RelocToApply();
    167   }
    168 
    169   bool error() { return HasError; }
    170 
    171 private:
    172   StringRef FileFormat;
    173   bool HasError;
    174 
    175   int64_t getAddend32LE(RelocationRef R) {
    176     const ELF32LEObjectFile *Obj = cast<ELF32LEObjectFile>(R.getObjectFile());
    177     DataRefImpl DRI = R.getRawDataRefImpl();
    178     int64_t Addend;
    179     Obj->getRelocationAddend(DRI, Addend);
    180     return Addend;
    181   }
    182 
    183   int64_t getAddend64LE(RelocationRef R) {
    184     const ELF64LEObjectFile *Obj = cast<ELF64LEObjectFile>(R.getObjectFile());
    185     DataRefImpl DRI = R.getRawDataRefImpl();
    186     int64_t Addend;
    187     Obj->getRelocationAddend(DRI, Addend);
    188     return Addend;
    189   }
    190 
    191   int64_t getAddend32BE(RelocationRef R) {
    192     const ELF32BEObjectFile *Obj = cast<ELF32BEObjectFile>(R.getObjectFile());
    193     DataRefImpl DRI = R.getRawDataRefImpl();
    194     int64_t Addend;
    195     Obj->getRelocationAddend(DRI, Addend);
    196     return Addend;
    197   }
    198 
    199   int64_t getAddend64BE(RelocationRef R) {
    200     const ELF64BEObjectFile *Obj = cast<ELF64BEObjectFile>(R.getObjectFile());
    201     DataRefImpl DRI = R.getRawDataRefImpl();
    202     int64_t Addend;
    203     Obj->getRelocationAddend(DRI, Addend);
    204     return Addend;
    205   }
    206   /// Operations
    207 
    208   /// 386-ELF
    209   RelocToApply visitELF_386_NONE(RelocationRef R) {
    210     return RelocToApply(0, 0);
    211   }
    212 
    213   // Ideally the Addend here will be the addend in the data for
    214   // the relocation. It's not actually the case for Rel relocations.
    215   RelocToApply visitELF_386_32(RelocationRef R, uint64_t Value) {
    216     int64_t Addend = getAddend32LE(R);
    217     return RelocToApply(Value + Addend, 4);
    218   }
    219 
    220   RelocToApply visitELF_386_PC32(RelocationRef R, uint64_t Value,
    221                                  uint64_t SecAddr) {
    222     int64_t Addend = getAddend32LE(R);
    223     uint64_t Address;
    224     R.getOffset(Address);
    225     return RelocToApply(Value + Addend - Address, 4);
    226   }
    227 
    228   /// X86-64 ELF
    229   RelocToApply visitELF_X86_64_NONE(RelocationRef R) {
    230     return RelocToApply(0, 0);
    231   }
    232   RelocToApply visitELF_X86_64_64(RelocationRef R, uint64_t Value) {
    233     int64_t Addend = getAddend64LE(R);
    234     return RelocToApply(Value + Addend, 8);
    235   }
    236   RelocToApply visitELF_X86_64_PC32(RelocationRef R, uint64_t Value,
    237                                     uint64_t SecAddr) {
    238     int64_t Addend = getAddend64LE(R);
    239     uint64_t Address;
    240     R.getOffset(Address);
    241     return RelocToApply(Value + Addend - Address, 4);
    242   }
    243   RelocToApply visitELF_X86_64_32(RelocationRef R, uint64_t Value) {
    244     int64_t Addend = getAddend64LE(R);
    245     uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
    246     return RelocToApply(Res, 4);
    247   }
    248   RelocToApply visitELF_X86_64_32S(RelocationRef R, uint64_t Value) {
    249     int64_t Addend = getAddend64LE(R);
    250     int32_t Res = (Value + Addend) & 0xFFFFFFFF;
    251     return RelocToApply(Res, 4);
    252   }
    253 
    254   /// PPC64 ELF
    255   RelocToApply visitELF_PPC64_ADDR32(RelocationRef R, uint64_t Value) {
    256     int64_t Addend;
    257     getELFRelocationAddend(R, Addend);
    258     uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
    259     return RelocToApply(Res, 4);
    260   }
    261   RelocToApply visitELF_PPC64_ADDR64(RelocationRef R, uint64_t Value) {
    262     int64_t Addend;
    263     getELFRelocationAddend(R, Addend);
    264     return RelocToApply(Value + Addend, 8);
    265   }
    266 
    267   /// PPC32 ELF
    268   RelocToApply visitELF_PPC_ADDR32(RelocationRef R, uint64_t Value) {
    269     int64_t Addend = getAddend32BE(R);
    270     uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
    271     return RelocToApply(Res, 4);
    272   }
    273 
    274   /// MIPS ELF
    275   RelocToApply visitELF_MIPS_32(RelocationRef R, uint64_t Value) {
    276     int64_t Addend;
    277     getELFRelocationAddend(R, Addend);
    278     uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
    279     return RelocToApply(Res, 4);
    280   }
    281 
    282   RelocToApply visitELF_MIPS_64(RelocationRef R, uint64_t Value) {
    283     int64_t Addend;
    284     getELFRelocationAddend(R, Addend);
    285     uint64_t Res = (Value + Addend);
    286     return RelocToApply(Res, 8);
    287   }
    288 
    289   // AArch64 ELF
    290   RelocToApply visitELF_AARCH64_ABS32(RelocationRef R, uint64_t Value) {
    291     int64_t Addend = getAddend64LE(R);
    292     int64_t Res =  Value + Addend;
    293 
    294     // Overflow check allows for both signed and unsigned interpretation.
    295     if (Res < INT32_MIN || Res > UINT32_MAX)
    296       HasError = true;
    297 
    298     return RelocToApply(static_cast<uint32_t>(Res), 4);
    299   }
    300 
    301   RelocToApply visitELF_AARCH64_ABS64(RelocationRef R, uint64_t Value) {
    302     int64_t Addend = getAddend64LE(R);
    303     return RelocToApply(Value + Addend, 8);
    304   }
    305 
    306   // SystemZ ELF
    307   RelocToApply visitELF_390_32(RelocationRef R, uint64_t Value) {
    308     int64_t Addend = getAddend64BE(R);
    309     int64_t Res = Value + Addend;
    310 
    311     // Overflow check allows for both signed and unsigned interpretation.
    312     if (Res < INT32_MIN || Res > UINT32_MAX)
    313       HasError = true;
    314 
    315     return RelocToApply(static_cast<uint32_t>(Res), 4);
    316   }
    317 
    318   RelocToApply visitELF_390_64(RelocationRef R, uint64_t Value) {
    319     int64_t Addend = getAddend64BE(R);
    320     return RelocToApply(Value + Addend, 8);
    321   }
    322 
    323   RelocToApply visitELF_SPARC_32(RelocationRef R, uint32_t Value) {
    324     int32_t Addend = getAddend32BE(R);
    325     return RelocToApply(Value + Addend, 4);
    326   }
    327 
    328   RelocToApply visitELF_SPARCV9_32(RelocationRef R, uint64_t Value) {
    329     int32_t Addend = getAddend64BE(R);
    330     return RelocToApply(Value + Addend, 4);
    331   }
    332 
    333   RelocToApply visitELF_SPARCV9_64(RelocationRef R, uint64_t Value) {
    334     int64_t Addend = getAddend64BE(R);
    335     return RelocToApply(Value + Addend, 8);
    336   }
    337 
    338   RelocToApply visitELF_ARM_ABS32(RelocationRef R, uint64_t Value) {
    339     int64_t Addend = getAddend32LE(R);
    340     return RelocToApply(Value + Addend, 4);
    341   }
    342 
    343 };
    344 
    345 }
    346 }
    347 #endif
    348