Home | History | Annotate | Download | only in MCTargetDesc
      1 //===-- X86ELFObjectWriter.cpp - X86 ELF Writer ---------------------------===//
      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 #include "MCTargetDesc/X86FixupKinds.h"
     11 #include "MCTargetDesc/X86MCTargetDesc.h"
     12 #include "llvm/MC/MCELFObjectWriter.h"
     13 #include "llvm/MC/MCExpr.h"
     14 #include "llvm/MC/MCValue.h"
     15 #include "llvm/Support/ELF.h"
     16 #include "llvm/Support/ErrorHandling.h"
     17 
     18 using namespace llvm;
     19 
     20 namespace {
     21   class X86ELFObjectWriter : public MCELFObjectTargetWriter {
     22   public:
     23     X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine);
     24 
     25     ~X86ELFObjectWriter() override;
     26 
     27   protected:
     28     unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
     29                           bool IsPCRel) const override;
     30   };
     31 }
     32 
     33 X86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI,
     34                                        uint16_t EMachine)
     35   : MCELFObjectTargetWriter(IsELF64, OSABI, EMachine,
     36                             // Only i386 uses Rel instead of RelA.
     37                             /*HasRelocationAddend*/ EMachine != ELF::EM_386) {}
     38 
     39 X86ELFObjectWriter::~X86ELFObjectWriter()
     40 {}
     41 
     42 enum X86_64RelType { RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 };
     43 
     44 static X86_64RelType getType64(unsigned Kind,
     45                                MCSymbolRefExpr::VariantKind &Modifier,
     46                                bool &IsPCRel) {
     47   switch (Kind) {
     48   default:
     49     llvm_unreachable("Unimplemented");
     50   case X86::reloc_global_offset_table8:
     51     Modifier = MCSymbolRefExpr::VK_GOT;
     52     IsPCRel = true;
     53     return RT64_64;
     54   case FK_Data_8:
     55     return RT64_64;
     56   case X86::reloc_signed_4byte:
     57     if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel)
     58       return RT64_32S;
     59     return RT64_32;
     60   case X86::reloc_global_offset_table:
     61     Modifier = MCSymbolRefExpr::VK_GOT;
     62     IsPCRel = true;
     63     return RT64_32;
     64   case FK_Data_4:
     65   case FK_PCRel_4:
     66   case X86::reloc_riprel_4byte:
     67   case X86::reloc_riprel_4byte_movq_load:
     68     return RT64_32;
     69   case FK_Data_2:
     70     return RT64_16;
     71   case FK_PCRel_1:
     72   case FK_Data_1:
     73     return RT64_8;
     74   }
     75 }
     76 
     77 static unsigned getRelocType64(MCSymbolRefExpr::VariantKind Modifier,
     78                                X86_64RelType Type, bool IsPCRel) {
     79   switch (Modifier) {
     80   default:
     81     llvm_unreachable("Unimplemented");
     82   case MCSymbolRefExpr::VK_None:
     83     switch (Type) {
     84     case RT64_64:
     85       return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64;
     86     case RT64_32:
     87       return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32;
     88     case RT64_32S:
     89       return ELF::R_X86_64_32S;
     90     case RT64_16:
     91       return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16;
     92     case RT64_8:
     93       return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8;
     94     }
     95   case MCSymbolRefExpr::VK_GOT:
     96     switch (Type) {
     97     case RT64_64:
     98       return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64;
     99     case RT64_32:
    100       return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32;
    101     case RT64_32S:
    102     case RT64_16:
    103     case RT64_8:
    104       llvm_unreachable("Unimplemented");
    105     }
    106   case MCSymbolRefExpr::VK_GOTOFF:
    107     assert(Type == RT64_64);
    108     assert(!IsPCRel);
    109     return ELF::R_X86_64_GOTOFF64;
    110   case MCSymbolRefExpr::VK_TPOFF:
    111     assert(!IsPCRel);
    112     switch (Type) {
    113     case RT64_64:
    114       return ELF::R_X86_64_TPOFF64;
    115     case RT64_32:
    116       return ELF::R_X86_64_TPOFF32;
    117     case RT64_32S:
    118     case RT64_16:
    119     case RT64_8:
    120       llvm_unreachable("Unimplemented");
    121     }
    122   case MCSymbolRefExpr::VK_DTPOFF:
    123     assert(!IsPCRel);
    124     switch (Type) {
    125     case RT64_64:
    126       return ELF::R_X86_64_DTPOFF64;
    127     case RT64_32:
    128       return ELF::R_X86_64_DTPOFF32;
    129     case RT64_32S:
    130     case RT64_16:
    131     case RT64_8:
    132       llvm_unreachable("Unimplemented");
    133     }
    134   case MCSymbolRefExpr::VK_SIZE:
    135     assert(!IsPCRel);
    136     switch (Type) {
    137     case RT64_64:
    138       return ELF::R_X86_64_SIZE64;
    139     case RT64_32:
    140       return ELF::R_X86_64_SIZE32;
    141     case RT64_32S:
    142     case RT64_16:
    143     case RT64_8:
    144       llvm_unreachable("Unimplemented");
    145     }
    146   case MCSymbolRefExpr::VK_TLSGD:
    147     assert(Type == RT64_32);
    148     return ELF::R_X86_64_TLSGD;
    149   case MCSymbolRefExpr::VK_GOTTPOFF:
    150     assert(Type == RT64_32);
    151     return ELF::R_X86_64_GOTTPOFF;
    152   case MCSymbolRefExpr::VK_TLSLD:
    153     assert(Type == RT64_32);
    154     return ELF::R_X86_64_TLSLD;
    155   case MCSymbolRefExpr::VK_PLT:
    156     assert(Type == RT64_32);
    157     return ELF::R_X86_64_PLT32;
    158   case MCSymbolRefExpr::VK_GOTPCREL:
    159     assert(Type == RT64_32);
    160     return ELF::R_X86_64_GOTPCREL;
    161   }
    162 }
    163 
    164 enum X86_32RelType { RT32_32, RT32_16, RT32_8 };
    165 
    166 static X86_32RelType getType32(X86_64RelType T) {
    167   switch (T) {
    168   case RT64_64:
    169     llvm_unreachable("Unimplemented");
    170   case RT64_32:
    171   case RT64_32S:
    172     return RT32_32;
    173   case RT64_16:
    174     return RT32_16;
    175   case RT64_8:
    176     return RT32_8;
    177   }
    178   llvm_unreachable("unexpected relocation type!");
    179 }
    180 
    181 static unsigned getRelocType32(MCSymbolRefExpr::VariantKind Modifier,
    182                                X86_32RelType Type, bool IsPCRel) {
    183   switch (Modifier) {
    184   default:
    185     llvm_unreachable("Unimplemented");
    186   case MCSymbolRefExpr::VK_None:
    187     switch (Type) {
    188     case RT32_32:
    189       return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32;
    190     case RT32_16:
    191       return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16;
    192     case RT32_8:
    193       return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8;
    194     }
    195   case MCSymbolRefExpr::VK_GOT:
    196     assert(Type == RT32_32);
    197     return IsPCRel ? ELF::R_386_GOTPC : ELF::R_386_GOT32;
    198   case MCSymbolRefExpr::VK_GOTOFF:
    199     assert(Type == RT32_32);
    200     assert(!IsPCRel);
    201     return ELF::R_386_GOTOFF;
    202   case MCSymbolRefExpr::VK_TPOFF:
    203     assert(Type == RT32_32);
    204     assert(!IsPCRel);
    205     return ELF::R_386_TLS_LE_32;
    206   case MCSymbolRefExpr::VK_DTPOFF:
    207     assert(Type == RT32_32);
    208     assert(!IsPCRel);
    209     return ELF::R_386_TLS_LDO_32;
    210   case MCSymbolRefExpr::VK_TLSGD:
    211     assert(Type == RT32_32);
    212     assert(!IsPCRel);
    213     return ELF::R_386_TLS_GD;
    214   case MCSymbolRefExpr::VK_GOTTPOFF:
    215     assert(Type == RT32_32);
    216     assert(!IsPCRel);
    217     return ELF::R_386_TLS_IE_32;
    218   case MCSymbolRefExpr::VK_PLT:
    219     assert(Type == RT32_32);
    220     return ELF::R_386_PLT32;
    221   case MCSymbolRefExpr::VK_INDNTPOFF:
    222     assert(Type == RT32_32);
    223     assert(!IsPCRel);
    224     return ELF::R_386_TLS_IE;
    225   case MCSymbolRefExpr::VK_NTPOFF:
    226     assert(Type == RT32_32);
    227     assert(!IsPCRel);
    228     return ELF::R_386_TLS_LE;
    229   case MCSymbolRefExpr::VK_GOTNTPOFF:
    230     assert(Type == RT32_32);
    231     assert(!IsPCRel);
    232     return ELF::R_386_TLS_GOTIE;
    233   case MCSymbolRefExpr::VK_TLSLDM:
    234     assert(Type == RT32_32);
    235     assert(!IsPCRel);
    236     return ELF::R_386_TLS_LDM;
    237   }
    238 }
    239 
    240 unsigned X86ELFObjectWriter::GetRelocType(const MCValue &Target,
    241                                           const MCFixup &Fixup,
    242                                           bool IsPCRel) const {
    243   MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
    244   X86_64RelType Type = getType64(Fixup.getKind(), Modifier, IsPCRel);
    245   if (getEMachine() == ELF::EM_X86_64)
    246     return getRelocType64(Modifier, Type, IsPCRel);
    247 
    248   assert(getEMachine() == ELF::EM_386 && "Unsupported ELF machine type.");
    249   return getRelocType32(Modifier, getType32(Type), IsPCRel);
    250 }
    251 
    252 MCObjectWriter *llvm::createX86ELFObjectWriter(raw_pwrite_stream &OS,
    253                                                bool IsELF64, uint8_t OSABI,
    254                                                uint16_t EMachine) {
    255   MCELFObjectTargetWriter *MOTW =
    256     new X86ELFObjectWriter(IsELF64, OSABI, EMachine);
    257   return createELFObjectWriter(MOTW, OS,  /*IsLittleEndian=*/true);
    258 }
    259