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/Triple.h"
     20 #include "llvm/BinaryFormat/ELF.h"
     21 #include "llvm/BinaryFormat/MachO.h"
     22 #include "llvm/Object/COFF.h"
     23 #include "llvm/Object/ELFObjectFile.h"
     24 #include "llvm/Object/MachO.h"
     25 #include "llvm/Object/ObjectFile.h"
     26 #include "llvm/Support/Casting.h"
     27 #include "llvm/Support/ErrorHandling.h"
     28 #include <cstdint>
     29 #include <system_error>
     30 
     31 namespace llvm {
     32 namespace object {
     33 
     34 /// @brief Base class for object file relocation visitors.
     35 class RelocVisitor {
     36 public:
     37   explicit RelocVisitor(const ObjectFile &Obj) : ObjToVisit(Obj) {}
     38 
     39   // TODO: Should handle multiple applied relocations via either passing in the
     40   // previously computed value or just count paired relocations as a single
     41   // visit.
     42   uint64_t visit(uint32_t Rel, RelocationRef R, uint64_t Value = 0) {
     43     if (isa<ELFObjectFileBase>(ObjToVisit))
     44       return visitELF(Rel, R, Value);
     45     if (isa<COFFObjectFile>(ObjToVisit))
     46       return visitCOFF(Rel, R, Value);
     47     if (isa<MachOObjectFile>(ObjToVisit))
     48       return visitMachO(Rel, R, Value);
     49 
     50     HasError = true;
     51     return 0;
     52   }
     53 
     54   bool error() { return HasError; }
     55 
     56 private:
     57   const ObjectFile &ObjToVisit;
     58   bool HasError = false;
     59 
     60   uint64_t visitELF(uint32_t Rel, RelocationRef R, uint64_t Value) {
     61     if (ObjToVisit.getBytesInAddress() == 8) { // 64-bit object file
     62       switch (ObjToVisit.getArch()) {
     63       case Triple::x86_64:
     64         return visitX86_64(Rel, R, Value);
     65       case Triple::aarch64:
     66       case Triple::aarch64_be:
     67         return visitAarch64(Rel, R, Value);
     68       case Triple::bpfel:
     69       case Triple::bpfeb:
     70         return visitBpf(Rel, R, Value);
     71       case Triple::mips64el:
     72       case Triple::mips64:
     73         return visitMips64(Rel, R, Value);
     74       case Triple::ppc64le:
     75       case Triple::ppc64:
     76         return visitPPC64(Rel, R, Value);
     77       case Triple::systemz:
     78         return visitSystemz(Rel, R, Value);
     79       case Triple::sparcv9:
     80         return visitSparc64(Rel, R, Value);
     81       case Triple::amdgcn:
     82         return visitAmdgpu(Rel, R, Value);
     83       default:
     84         HasError = true;
     85         return 0;
     86       }
     87     }
     88 
     89     // 32-bit object file
     90     assert(ObjToVisit.getBytesInAddress() == 4 &&
     91            "Invalid word size in object file");
     92 
     93     switch (ObjToVisit.getArch()) {
     94     case Triple::x86:
     95       return visitX86(Rel, R, Value);
     96     case Triple::ppc:
     97       return visitPPC32(Rel, R, Value);
     98     case Triple::arm:
     99     case Triple::armeb:
    100       return visitARM(Rel, R, Value);
    101     case Triple::lanai:
    102       return visitLanai(Rel, R, Value);
    103     case Triple::mipsel:
    104     case Triple::mips:
    105       return visitMips32(Rel, R, Value);
    106     case Triple::sparc:
    107       return visitSparc32(Rel, R, Value);
    108     case Triple::hexagon:
    109       return visitHexagon(Rel, R, Value);
    110     default:
    111       HasError = true;
    112       return 0;
    113     }
    114   }
    115 
    116   int64_t getELFAddend(RelocationRef R) {
    117     Expected<int64_t> AddendOrErr = ELFRelocationRef(R).getAddend();
    118     handleAllErrors(AddendOrErr.takeError(), [](const ErrorInfoBase &EI) {
    119       report_fatal_error(EI.message());
    120     });
    121     return *AddendOrErr;
    122   }
    123 
    124   uint64_t visitX86_64(uint32_t Rel, RelocationRef R, uint64_t Value) {
    125     switch (Rel) {
    126     case ELF::R_X86_64_NONE:
    127       return 0;
    128     case ELF::R_X86_64_64:
    129       return Value + getELFAddend(R);
    130     case ELF::R_X86_64_PC32:
    131       return Value + getELFAddend(R) - R.getOffset();
    132     case ELF::R_X86_64_32:
    133     case ELF::R_X86_64_32S:
    134       return (Value + getELFAddend(R)) & 0xFFFFFFFF;
    135     }
    136     HasError = true;
    137     return 0;
    138   }
    139 
    140   uint64_t visitAarch64(uint32_t Rel, RelocationRef R, uint64_t Value) {
    141     switch (Rel) {
    142     case ELF::R_AARCH64_ABS32: {
    143       int64_t Res = Value + getELFAddend(R);
    144       if (Res < INT32_MIN || Res > UINT32_MAX)
    145         HasError = true;
    146       return static_cast<uint32_t>(Res);
    147     }
    148     case ELF::R_AARCH64_ABS64:
    149       return Value + getELFAddend(R);
    150     }
    151     HasError = true;
    152     return 0;
    153   }
    154 
    155   uint64_t visitBpf(uint32_t Rel, RelocationRef R, uint64_t Value) {
    156     switch (Rel) {
    157     case ELF::R_BPF_64_32:
    158       return Value & 0xFFFFFFFF;
    159     case ELF::R_BPF_64_64:
    160       return Value;
    161     }
    162     HasError = true;
    163     return 0;
    164   }
    165 
    166   uint64_t visitMips64(uint32_t Rel, RelocationRef R, uint64_t Value) {
    167     switch (Rel) {
    168     case ELF::R_MIPS_32:
    169       return (Value + getELFAddend(R)) & 0xFFFFFFFF;
    170     case ELF::R_MIPS_64:
    171       return Value + getELFAddend(R);
    172     case ELF::R_MIPS_TLS_DTPREL64:
    173       return Value + getELFAddend(R) - 0x8000;
    174     }
    175     HasError = true;
    176     return 0;
    177   }
    178 
    179   uint64_t visitPPC64(uint32_t Rel, RelocationRef R, uint64_t Value) {
    180     switch (Rel) {
    181     case ELF::R_PPC64_ADDR32:
    182       return (Value + getELFAddend(R)) & 0xFFFFFFFF;
    183     case ELF::R_PPC64_ADDR64:
    184       return Value + getELFAddend(R);
    185     }
    186     HasError = true;
    187     return 0;
    188   }
    189 
    190   uint64_t visitSystemz(uint32_t Rel, RelocationRef R, uint64_t Value) {
    191     switch (Rel) {
    192     case ELF::R_390_32: {
    193       int64_t Res = Value + getELFAddend(R);
    194       if (Res < INT32_MIN || Res > UINT32_MAX)
    195         HasError = true;
    196       return static_cast<uint32_t>(Res);
    197     }
    198     case ELF::R_390_64:
    199       return Value + getELFAddend(R);
    200     }
    201     HasError = true;
    202     return 0;
    203   }
    204 
    205   uint64_t visitSparc64(uint32_t Rel, RelocationRef R, uint64_t Value) {
    206     switch (Rel) {
    207     case ELF::R_SPARC_32:
    208     case ELF::R_SPARC_64:
    209     case ELF::R_SPARC_UA32:
    210     case ELF::R_SPARC_UA64:
    211       return Value + getELFAddend(R);
    212     }
    213     HasError = true;
    214     return 0;
    215   }
    216 
    217   uint64_t visitAmdgpu(uint32_t Rel, RelocationRef R, uint64_t Value) {
    218     switch (Rel) {
    219     case ELF::R_AMDGPU_ABS32:
    220     case ELF::R_AMDGPU_ABS64:
    221       return Value + getELFAddend(R);
    222     }
    223     HasError = true;
    224     return 0;
    225   }
    226 
    227   uint64_t visitX86(uint32_t Rel, RelocationRef R, uint64_t Value) {
    228     switch (Rel) {
    229     case ELF::R_386_NONE:
    230       return 0;
    231     case ELF::R_386_32:
    232       return Value;
    233     case ELF::R_386_PC32:
    234       return Value - R.getOffset();
    235     }
    236     HasError = true;
    237     return 0;
    238   }
    239 
    240   uint64_t visitPPC32(uint32_t Rel, RelocationRef R, uint64_t Value) {
    241     if (Rel == ELF::R_PPC_ADDR32)
    242       return (Value + getELFAddend(R)) & 0xFFFFFFFF;
    243     HasError = true;
    244     return 0;
    245   }
    246 
    247   uint64_t visitARM(uint32_t Rel, RelocationRef R, uint64_t Value) {
    248     if (Rel == ELF::R_ARM_ABS32) {
    249       if ((int64_t)Value < INT32_MIN || (int64_t)Value > UINT32_MAX)
    250         HasError = true;
    251       return static_cast<uint32_t>(Value);
    252     }
    253     HasError = true;
    254     return 0;
    255   }
    256 
    257   uint64_t visitLanai(uint32_t Rel, RelocationRef R, uint64_t Value) {
    258     if (Rel == ELF::R_LANAI_32)
    259       return (Value + getELFAddend(R)) & 0xFFFFFFFF;
    260     HasError = true;
    261     return 0;
    262   }
    263 
    264   uint64_t visitMips32(uint32_t Rel, RelocationRef R, uint64_t Value) {
    265     // FIXME: Take in account implicit addends to get correct results.
    266     if (Rel == ELF::R_MIPS_32)
    267       return Value & 0xFFFFFFFF;
    268     if (Rel == ELF::R_MIPS_TLS_DTPREL32)
    269       return Value & 0xFFFFFFFF;
    270     HasError = true;
    271     return 0;
    272   }
    273 
    274   uint64_t visitSparc32(uint32_t Rel, RelocationRef R, uint64_t Value) {
    275     if (Rel == ELF::R_SPARC_32 || Rel == ELF::R_SPARC_UA32)
    276       return Value + getELFAddend(R);
    277     HasError = true;
    278     return 0;
    279   }
    280 
    281   uint64_t visitHexagon(uint32_t Rel, RelocationRef R, uint64_t Value) {
    282     if (Rel == ELF::R_HEX_32)
    283       return Value + getELFAddend(R);
    284     HasError = true;
    285     return 0;
    286   }
    287 
    288   uint64_t visitCOFF(uint32_t Rel, RelocationRef R, uint64_t Value) {
    289     switch (ObjToVisit.getArch()) {
    290     case Triple::x86:
    291       switch (Rel) {
    292       case COFF::IMAGE_REL_I386_SECREL:
    293       case COFF::IMAGE_REL_I386_DIR32:
    294         return static_cast<uint32_t>(Value);
    295       }
    296       break;
    297     case Triple::x86_64:
    298       switch (Rel) {
    299       case COFF::IMAGE_REL_AMD64_SECREL:
    300         return static_cast<uint32_t>(Value);
    301       case COFF::IMAGE_REL_AMD64_ADDR64:
    302         return Value;
    303       }
    304       break;
    305     }
    306     HasError = true;
    307     return 0;
    308   }
    309 
    310   uint64_t visitMachO(uint32_t Rel, RelocationRef R, uint64_t Value) {
    311     if (ObjToVisit.getArch() == Triple::x86_64 &&
    312         Rel == MachO::X86_64_RELOC_UNSIGNED)
    313       return Value;
    314     HasError = true;
    315     return 0;
    316   }
    317 };
    318 
    319 } // end namespace object
    320 } // end namespace llvm
    321 
    322 #endif // LLVM_OBJECT_RELOCVISITOR_H
    323