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/MCAsmInfo.h"
     13 #include "llvm/MC/MCContext.h"
     14 #include "llvm/MC/MCELFObjectWriter.h"
     15 #include "llvm/MC/MCExpr.h"
     16 #include "llvm/MC/MCValue.h"
     17 #include "llvm/Support/ELF.h"
     18 #include "llvm/Support/ErrorHandling.h"
     19 
     20 using namespace llvm;
     21 
     22 namespace {
     23   class X86ELFObjectWriter : public MCELFObjectTargetWriter {
     24   public:
     25     X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine);
     26 
     27     ~X86ELFObjectWriter() override;
     28 
     29   protected:
     30     unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
     31                           const MCFixup &Fixup, bool IsPCRel) const override;
     32   };
     33 }
     34 
     35 X86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI,
     36                                        uint16_t EMachine)
     37     : MCELFObjectTargetWriter(IsELF64, OSABI, EMachine,
     38                               // Only i386 and IAMCU use Rel instead of RelA.
     39                               /*HasRelocationAddend*/
     40                               (EMachine != ELF::EM_386) &&
     41                                   (EMachine != ELF::EM_IAMCU)) {}
     42 
     43 X86ELFObjectWriter::~X86ELFObjectWriter()
     44 {}
     45 
     46 enum X86_64RelType { RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 };
     47 
     48 static X86_64RelType getType64(unsigned Kind,
     49                                MCSymbolRefExpr::VariantKind &Modifier,
     50                                bool &IsPCRel) {
     51   switch (Kind) {
     52   default:
     53     llvm_unreachable("Unimplemented");
     54   case X86::reloc_global_offset_table8:
     55     Modifier = MCSymbolRefExpr::VK_GOT;
     56     IsPCRel = true;
     57     return RT64_64;
     58   case FK_Data_8:
     59     return RT64_64;
     60   case X86::reloc_signed_4byte:
     61   case X86::reloc_signed_4byte_relax:
     62     if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel)
     63       return RT64_32S;
     64     return RT64_32;
     65   case X86::reloc_global_offset_table:
     66     Modifier = MCSymbolRefExpr::VK_GOT;
     67     IsPCRel = true;
     68     return RT64_32;
     69   case FK_Data_4:
     70   case FK_PCRel_4:
     71   case X86::reloc_riprel_4byte:
     72   case X86::reloc_riprel_4byte_relax:
     73   case X86::reloc_riprel_4byte_relax_rex:
     74   case X86::reloc_riprel_4byte_movq_load:
     75     return RT64_32;
     76   case FK_PCRel_2:
     77   case FK_Data_2:
     78     return RT64_16;
     79   case FK_PCRel_1:
     80   case FK_Data_1:
     81     return RT64_8;
     82   }
     83 }
     84 
     85 static void checkIs32(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) {
     86   if (Type != RT64_32)
     87     Ctx.reportError(Loc,
     88                     "32 bit reloc applied to a field with a different size");
     89 }
     90 
     91 static unsigned getRelocType64(MCContext &Ctx, SMLoc Loc,
     92                                MCSymbolRefExpr::VariantKind Modifier,
     93                                X86_64RelType Type, bool IsPCRel,
     94                                unsigned Kind) {
     95   switch (Modifier) {
     96   default:
     97     llvm_unreachable("Unimplemented");
     98   case MCSymbolRefExpr::VK_None:
     99     switch (Type) {
    100     case RT64_64:
    101       return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64;
    102     case RT64_32:
    103       return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32;
    104     case RT64_32S:
    105       return ELF::R_X86_64_32S;
    106     case RT64_16:
    107       return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16;
    108     case RT64_8:
    109       return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8;
    110     }
    111   case MCSymbolRefExpr::VK_GOT:
    112     switch (Type) {
    113     case RT64_64:
    114       return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64;
    115     case RT64_32:
    116       return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32;
    117     case RT64_32S:
    118     case RT64_16:
    119     case RT64_8:
    120       llvm_unreachable("Unimplemented");
    121     }
    122   case MCSymbolRefExpr::VK_GOTOFF:
    123     assert(Type == RT64_64);
    124     assert(!IsPCRel);
    125     return ELF::R_X86_64_GOTOFF64;
    126   case MCSymbolRefExpr::VK_TPOFF:
    127     assert(!IsPCRel);
    128     switch (Type) {
    129     case RT64_64:
    130       return ELF::R_X86_64_TPOFF64;
    131     case RT64_32:
    132       return ELF::R_X86_64_TPOFF32;
    133     case RT64_32S:
    134     case RT64_16:
    135     case RT64_8:
    136       llvm_unreachable("Unimplemented");
    137     }
    138   case MCSymbolRefExpr::VK_DTPOFF:
    139     assert(!IsPCRel);
    140     switch (Type) {
    141     case RT64_64:
    142       return ELF::R_X86_64_DTPOFF64;
    143     case RT64_32:
    144       return ELF::R_X86_64_DTPOFF32;
    145     case RT64_32S:
    146     case RT64_16:
    147     case RT64_8:
    148       llvm_unreachable("Unimplemented");
    149     }
    150   case MCSymbolRefExpr::VK_SIZE:
    151     assert(!IsPCRel);
    152     switch (Type) {
    153     case RT64_64:
    154       return ELF::R_X86_64_SIZE64;
    155     case RT64_32:
    156       return ELF::R_X86_64_SIZE32;
    157     case RT64_32S:
    158     case RT64_16:
    159     case RT64_8:
    160       llvm_unreachable("Unimplemented");
    161     }
    162   case MCSymbolRefExpr::VK_TLSCALL:
    163     return ELF::R_X86_64_TLSDESC_CALL;
    164   case MCSymbolRefExpr::VK_TLSDESC:
    165     return ELF::R_X86_64_GOTPC32_TLSDESC;
    166   case MCSymbolRefExpr::VK_TLSGD:
    167     checkIs32(Ctx, Loc, Type);
    168     return ELF::R_X86_64_TLSGD;
    169   case MCSymbolRefExpr::VK_GOTTPOFF:
    170     checkIs32(Ctx, Loc, Type);
    171     return ELF::R_X86_64_GOTTPOFF;
    172   case MCSymbolRefExpr::VK_TLSLD:
    173     checkIs32(Ctx, Loc, Type);
    174     return ELF::R_X86_64_TLSLD;
    175   case MCSymbolRefExpr::VK_PLT:
    176     checkIs32(Ctx, Loc, Type);
    177     return ELF::R_X86_64_PLT32;
    178   case MCSymbolRefExpr::VK_GOTPCREL:
    179     checkIs32(Ctx, Loc, Type);
    180     // Older versions of ld.bfd/ld.gold/lld
    181     // do not support GOTPCRELX/REX_GOTPCRELX,
    182     // and we want to keep back-compatibility.
    183     if (!Ctx.getAsmInfo()->canRelaxRelocations())
    184       return ELF::R_X86_64_GOTPCREL;
    185     switch (Kind) {
    186     default:
    187       return ELF::R_X86_64_GOTPCREL;
    188     case X86::reloc_riprel_4byte_relax:
    189       return ELF::R_X86_64_GOTPCRELX;
    190     case X86::reloc_riprel_4byte_relax_rex:
    191     case X86::reloc_riprel_4byte_movq_load:
    192       return ELF::R_X86_64_REX_GOTPCRELX;
    193     }
    194   }
    195 }
    196 
    197 enum X86_32RelType { RT32_32, RT32_16, RT32_8 };
    198 
    199 static X86_32RelType getType32(X86_64RelType T) {
    200   switch (T) {
    201   case RT64_64:
    202     llvm_unreachable("Unimplemented");
    203   case RT64_32:
    204   case RT64_32S:
    205     return RT32_32;
    206   case RT64_16:
    207     return RT32_16;
    208   case RT64_8:
    209     return RT32_8;
    210   }
    211   llvm_unreachable("unexpected relocation type!");
    212 }
    213 
    214 static unsigned getRelocType32(MCContext &Ctx,
    215                                MCSymbolRefExpr::VariantKind Modifier,
    216                                X86_32RelType Type, bool IsPCRel,
    217                                unsigned Kind) {
    218   switch (Modifier) {
    219   default:
    220     llvm_unreachable("Unimplemented");
    221   case MCSymbolRefExpr::VK_None:
    222     switch (Type) {
    223     case RT32_32:
    224       return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32;
    225     case RT32_16:
    226       return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16;
    227     case RT32_8:
    228       return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8;
    229     }
    230   case MCSymbolRefExpr::VK_GOT:
    231     assert(Type == RT32_32);
    232     if (IsPCRel)
    233       return ELF::R_386_GOTPC;
    234     // Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we
    235     // want to maintain compatibility.
    236     if (!Ctx.getAsmInfo()->canRelaxRelocations())
    237       return ELF::R_386_GOT32;
    238 
    239     return Kind == X86::reloc_signed_4byte_relax ? ELF::R_386_GOT32X
    240                                                  : ELF::R_386_GOT32;
    241   case MCSymbolRefExpr::VK_GOTOFF:
    242     assert(Type == RT32_32);
    243     assert(!IsPCRel);
    244     return ELF::R_386_GOTOFF;
    245   case MCSymbolRefExpr::VK_TPOFF:
    246     assert(Type == RT32_32);
    247     assert(!IsPCRel);
    248     return ELF::R_386_TLS_LE_32;
    249   case MCSymbolRefExpr::VK_DTPOFF:
    250     assert(Type == RT32_32);
    251     assert(!IsPCRel);
    252     return ELF::R_386_TLS_LDO_32;
    253   case MCSymbolRefExpr::VK_TLSGD:
    254     assert(Type == RT32_32);
    255     assert(!IsPCRel);
    256     return ELF::R_386_TLS_GD;
    257   case MCSymbolRefExpr::VK_GOTTPOFF:
    258     assert(Type == RT32_32);
    259     assert(!IsPCRel);
    260     return ELF::R_386_TLS_IE_32;
    261   case MCSymbolRefExpr::VK_PLT:
    262     assert(Type == RT32_32);
    263     return ELF::R_386_PLT32;
    264   case MCSymbolRefExpr::VK_INDNTPOFF:
    265     assert(Type == RT32_32);
    266     assert(!IsPCRel);
    267     return ELF::R_386_TLS_IE;
    268   case MCSymbolRefExpr::VK_NTPOFF:
    269     assert(Type == RT32_32);
    270     assert(!IsPCRel);
    271     return ELF::R_386_TLS_LE;
    272   case MCSymbolRefExpr::VK_GOTNTPOFF:
    273     assert(Type == RT32_32);
    274     assert(!IsPCRel);
    275     return ELF::R_386_TLS_GOTIE;
    276   case MCSymbolRefExpr::VK_TLSLDM:
    277     assert(Type == RT32_32);
    278     assert(!IsPCRel);
    279     return ELF::R_386_TLS_LDM;
    280   }
    281 }
    282 
    283 unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
    284                                           const MCFixup &Fixup,
    285                                           bool IsPCRel) const {
    286   MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
    287   unsigned Kind = Fixup.getKind();
    288   X86_64RelType Type = getType64(Kind, Modifier, IsPCRel);
    289   if (getEMachine() == ELF::EM_X86_64)
    290     return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel, Kind);
    291 
    292   assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) &&
    293          "Unsupported ELF machine type.");
    294   return getRelocType32(Ctx, Modifier, getType32(Type), IsPCRel, Kind);
    295 }
    296 
    297 MCObjectWriter *llvm::createX86ELFObjectWriter(raw_pwrite_stream &OS,
    298                                                bool IsELF64, uint8_t OSABI,
    299                                                uint16_t EMachine) {
    300   MCELFObjectTargetWriter *MOTW =
    301     new X86ELFObjectWriter(IsELF64, OSABI, EMachine);
    302   return createELFObjectWriter(MOTW, OS,  /*IsLittleEndian=*/true);
    303 }
    304