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/ObjectFile.h"
     21 #include "llvm/Object/ELF.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(const RelocToApply &In) : Value(In.Value), Width(In.Width) {}
     37   RelocToApply(int64_t Value, char Width) : Value(Value), Width(Width) {}
     38   RelocToApply() : Value(0), Width(0) {}
     39 };
     40 
     41 /// @brief Base class for object file relocation visitors.
     42 class RelocVisitor {
     43 public:
     44   explicit RelocVisitor(StringRef FileFormat)
     45     : FileFormat(FileFormat), 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 SecAddr = 0,
     51                      uint64_t Value = 0) {
     52     if (FileFormat == "ELF64-x86-64") {
     53       switch (RelocType) {
     54         case llvm::ELF::R_X86_64_NONE:
     55           return visitELF_X86_64_NONE(R);
     56         case llvm::ELF::R_X86_64_64:
     57           return visitELF_X86_64_64(R, Value);
     58         case llvm::ELF::R_X86_64_PC32:
     59           return visitELF_X86_64_PC32(R, Value, SecAddr);
     60         case llvm::ELF::R_X86_64_32:
     61           return visitELF_X86_64_32(R, Value);
     62         case llvm::ELF::R_X86_64_32S:
     63           return visitELF_X86_64_32S(R, Value);
     64         default:
     65           HasError = true;
     66           return RelocToApply();
     67       }
     68     } else if (FileFormat == "ELF32-i386") {
     69       switch (RelocType) {
     70       case llvm::ELF::R_386_NONE:
     71         return visitELF_386_NONE(R);
     72       case llvm::ELF::R_386_32:
     73         return visitELF_386_32(R, Value);
     74       case llvm::ELF::R_386_PC32:
     75         return visitELF_386_PC32(R, Value, SecAddr);
     76       default:
     77         HasError = true;
     78         return RelocToApply();
     79       }
     80     } else if (FileFormat == "ELF64-ppc64") {
     81       switch (RelocType) {
     82       case llvm::ELF::R_PPC64_ADDR32:
     83         return visitELF_PPC64_ADDR32(R, Value);
     84       case llvm::ELF::R_PPC64_ADDR64:
     85         return visitELF_PPC64_ADDR64(R, Value);
     86       default:
     87         HasError = true;
     88         return RelocToApply();
     89       }
     90     } else if (FileFormat == "ELF32-ppc") {
     91       switch (RelocType) {
     92       case llvm::ELF::R_PPC_ADDR32:
     93         return visitELF_PPC_ADDR32(R, Value);
     94       default:
     95         HasError = true;
     96         return RelocToApply();
     97       }
     98     } else if (FileFormat == "ELF32-mips") {
     99       switch (RelocType) {
    100       case llvm::ELF::R_MIPS_32:
    101         return visitELF_MIPS_32(R, Value);
    102       default:
    103         HasError = true;
    104         return RelocToApply();
    105       }
    106     } else if (FileFormat == "ELF64-aarch64") {
    107       switch (RelocType) {
    108       case llvm::ELF::R_AARCH64_ABS32:
    109         return visitELF_AARCH64_ABS32(R, Value);
    110       case llvm::ELF::R_AARCH64_ABS64:
    111         return visitELF_AARCH64_ABS64(R, Value);
    112       default:
    113         HasError = true;
    114         return RelocToApply();
    115       }
    116     } else if (FileFormat == "ELF64-s390") {
    117       switch (RelocType) {
    118       case llvm::ELF::R_390_32:
    119         return visitELF_390_32(R, Value);
    120       case llvm::ELF::R_390_64:
    121         return visitELF_390_64(R, Value);
    122       default:
    123         HasError = true;
    124         return RelocToApply();
    125       }
    126     }
    127     HasError = true;
    128     return RelocToApply();
    129   }
    130 
    131   bool error() { return HasError; }
    132 
    133 private:
    134   StringRef FileFormat;
    135   bool HasError;
    136 
    137   int64_t getAddend32LE(RelocationRef R) {
    138     const ELF32LEObjectFile *Obj = cast<ELF32LEObjectFile>(R.getObjectFile());
    139     DataRefImpl DRI = R.getRawDataRefImpl();
    140     int64_t Addend;
    141     Obj->getRelocationAddend(DRI, Addend);
    142     return Addend;
    143   }
    144 
    145   int64_t getAddend64LE(RelocationRef R) {
    146     const ELF64LEObjectFile *Obj = cast<ELF64LEObjectFile>(R.getObjectFile());
    147     DataRefImpl DRI = R.getRawDataRefImpl();
    148     int64_t Addend;
    149     Obj->getRelocationAddend(DRI, Addend);
    150     return Addend;
    151   }
    152 
    153   int64_t getAddend32BE(RelocationRef R) {
    154     const ELF32BEObjectFile *Obj = cast<ELF32BEObjectFile>(R.getObjectFile());
    155     DataRefImpl DRI = R.getRawDataRefImpl();
    156     int64_t Addend;
    157     Obj->getRelocationAddend(DRI, Addend);
    158     return Addend;
    159   }
    160 
    161   int64_t getAddend64BE(RelocationRef R) {
    162     const ELF64BEObjectFile *Obj = cast<ELF64BEObjectFile>(R.getObjectFile());
    163     DataRefImpl DRI = R.getRawDataRefImpl();
    164     int64_t Addend;
    165     Obj->getRelocationAddend(DRI, Addend);
    166     return Addend;
    167   }
    168   /// Operations
    169 
    170   /// 386-ELF
    171   RelocToApply visitELF_386_NONE(RelocationRef R) {
    172     return RelocToApply(0, 0);
    173   }
    174 
    175   // Ideally the Addend here will be the addend in the data for
    176   // the relocation. It's not actually the case for Rel relocations.
    177   RelocToApply visitELF_386_32(RelocationRef R, uint64_t Value) {
    178     int64_t Addend = getAddend32LE(R);
    179     return RelocToApply(Value + Addend, 4);
    180   }
    181 
    182   RelocToApply visitELF_386_PC32(RelocationRef R, uint64_t Value,
    183                                  uint64_t SecAddr) {
    184     int64_t Addend = getAddend32LE(R);
    185     uint64_t Address;
    186     R.getOffset(Address);
    187     return RelocToApply(Value + Addend - Address, 4);
    188   }
    189 
    190   /// X86-64 ELF
    191   RelocToApply visitELF_X86_64_NONE(RelocationRef R) {
    192     return RelocToApply(0, 0);
    193   }
    194   RelocToApply visitELF_X86_64_64(RelocationRef R, uint64_t Value) {
    195     int64_t Addend = getAddend64LE(R);
    196     return RelocToApply(Value + Addend, 8);
    197   }
    198   RelocToApply visitELF_X86_64_PC32(RelocationRef R, uint64_t Value,
    199                                     uint64_t SecAddr) {
    200     int64_t Addend = getAddend64LE(R);
    201     uint64_t Address;
    202     R.getOffset(Address);
    203     return RelocToApply(Value + Addend - Address, 4);
    204   }
    205   RelocToApply visitELF_X86_64_32(RelocationRef R, uint64_t Value) {
    206     int64_t Addend = getAddend64LE(R);
    207     uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
    208     return RelocToApply(Res, 4);
    209   }
    210   RelocToApply visitELF_X86_64_32S(RelocationRef R, uint64_t Value) {
    211     int64_t Addend = getAddend64LE(R);
    212     int32_t Res = (Value + Addend) & 0xFFFFFFFF;
    213     return RelocToApply(Res, 4);
    214   }
    215 
    216   /// PPC64 ELF
    217   RelocToApply visitELF_PPC64_ADDR32(RelocationRef R, uint64_t Value) {
    218     int64_t Addend = getAddend64BE(R);
    219     uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
    220     return RelocToApply(Res, 4);
    221   }
    222   RelocToApply visitELF_PPC64_ADDR64(RelocationRef R, uint64_t Value) {
    223     int64_t Addend = getAddend64BE(R);
    224     return RelocToApply(Value + Addend, 8);
    225   }
    226 
    227   /// PPC32 ELF
    228   RelocToApply visitELF_PPC_ADDR32(RelocationRef R, uint64_t Value) {
    229     int64_t Addend = getAddend32BE(R);
    230     uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
    231     return RelocToApply(Res, 4);
    232   }
    233 
    234   /// MIPS ELF
    235   RelocToApply visitELF_MIPS_32(RelocationRef R, uint64_t Value) {
    236     int64_t Addend;
    237     getELFRelocationAddend(R, Addend);
    238     uint32_t Res = (Value + Addend) & 0xFFFFFFFF;
    239     return RelocToApply(Res, 4);
    240   }
    241 
    242   // AArch64 ELF
    243   RelocToApply visitELF_AARCH64_ABS32(RelocationRef R, uint64_t Value) {
    244     int64_t Addend = getAddend64LE(R);
    245     int64_t Res =  Value + Addend;
    246 
    247     // Overflow check allows for both signed and unsigned interpretation.
    248     if (Res < INT32_MIN || Res > UINT32_MAX)
    249       HasError = true;
    250 
    251     return RelocToApply(static_cast<uint32_t>(Res), 4);
    252   }
    253 
    254   RelocToApply visitELF_AARCH64_ABS64(RelocationRef R, uint64_t Value) {
    255     int64_t Addend = getAddend64LE(R);
    256     return RelocToApply(Value + Addend, 8);
    257   }
    258 
    259   // SystemZ ELF
    260   RelocToApply visitELF_390_32(RelocationRef R, uint64_t Value) {
    261     int64_t Addend = getAddend64BE(R);
    262     int64_t Res = Value + Addend;
    263 
    264     // Overflow check allows for both signed and unsigned interpretation.
    265     if (Res < INT32_MIN || Res > UINT32_MAX)
    266       HasError = true;
    267 
    268     return RelocToApply(static_cast<uint32_t>(Res), 4);
    269   }
    270 
    271   RelocToApply visitELF_390_64(RelocationRef R, uint64_t Value) {
    272     int64_t Addend = getAddend64BE(R);
    273     return RelocToApply(Value + Addend, 8);
    274   }
    275 };
    276 
    277 }
    278 }
    279 #endif
    280