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