Home | History | Annotate | Download | only in MCTargetDesc
      1 //===-- ARMELFObjectWriter.cpp - ARM 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/ARMMCTargetDesc.h"
     11 #include "MCTargetDesc/ARMFixupKinds.h"
     12 #include "llvm/ADT/Statistic.h"
     13 #include "llvm/ADT/StringSwitch.h"
     14 #include "llvm/MC/MCELFObjectWriter.h"
     15 #include "llvm/MC/MCExpr.h"
     16 #include "llvm/MC/MCSectionELF.h"
     17 #include "llvm/MC/MCValue.h"
     18 #include "llvm/Support/Debug.h"
     19 #include "llvm/Support/ErrorHandling.h"
     20 #include "llvm/Support/raw_ostream.h"
     21 
     22 using namespace llvm;
     23 
     24 namespace {
     25   class ARMELFObjectWriter : public MCELFObjectTargetWriter {
     26     enum { DefaultEABIVersion = 0x05000000U };
     27     unsigned GetRelocTypeInner(const MCValue &Target,
     28                                const MCFixup &Fixup,
     29                                bool IsPCRel) const;
     30 
     31 
     32   public:
     33     ARMELFObjectWriter(uint8_t OSABI);
     34 
     35     virtual ~ARMELFObjectWriter();
     36 
     37     virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
     38                                   bool IsPCRel, bool IsRelocWithSymbol,
     39                                   int64_t Addend) const;
     40     virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm,
     41                                    const MCValue &Target,
     42                                    const MCFragment &F,
     43                                    const MCFixup &Fixup,
     44                                    bool IsPCRel) const;
     45   };
     46 }
     47 
     48 ARMELFObjectWriter::ARMELFObjectWriter(uint8_t OSABI)
     49   : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI,
     50                             ELF::EM_ARM,
     51                             /*HasRelocationAddend*/ false) {}
     52 
     53 ARMELFObjectWriter::~ARMELFObjectWriter() {}
     54 
     55 // In ARM, _MergedGlobals and other most symbols get emitted directly.
     56 // I.e. not as an offset to a section symbol.
     57 // This code is an approximation of what ARM/gcc does.
     58 
     59 STATISTIC(PCRelCount, "Total number of PIC Relocations");
     60 STATISTIC(NonPCRelCount, "Total number of non-PIC relocations");
     61 
     62 const MCSymbol *ARMELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm,
     63                                                    const MCValue &Target,
     64                                                    const MCFragment &F,
     65                                                    const MCFixup &Fixup,
     66                                                    bool IsPCRel) const {
     67   const MCSymbol &Symbol = Target.getSymA()->getSymbol().AliasedSymbol();
     68   bool EmitThisSym = false;
     69 
     70   const MCSectionELF &Section =
     71     static_cast<const MCSectionELF&>(Symbol.getSection());
     72   bool InNormalSection = true;
     73   unsigned RelocType = 0;
     74   RelocType = GetRelocTypeInner(Target, Fixup, IsPCRel);
     75 
     76   DEBUG(
     77       const MCSymbolRefExpr::VariantKind Kind = Target.getSymA()->getKind();
     78       MCSymbolRefExpr::VariantKind Kind2;
     79       Kind2 = Target.getSymB() ?  Target.getSymB()->getKind() :
     80         MCSymbolRefExpr::VK_None;
     81       dbgs() << "considering symbol "
     82         << Section.getSectionName() << "/"
     83         << Symbol.getName() << "/"
     84         << " Rel:" << (unsigned)RelocType
     85         << " Kind: " << (int)Kind << "/" << (int)Kind2
     86         << " Tmp:"
     87         << Symbol.isAbsolute() << "/" << Symbol.isDefined() << "/"
     88         << Symbol.isVariable() << "/" << Symbol.isTemporary()
     89         << " Counts:" << PCRelCount << "/" << NonPCRelCount << "\n");
     90 
     91   if (IsPCRel) { ++PCRelCount;
     92     switch (RelocType) {
     93     default:
     94       // Most relocation types are emitted as explicit symbols
     95       InNormalSection =
     96         StringSwitch<bool>(Section.getSectionName())
     97         .Case(".data.rel.ro.local", false)
     98         .Case(".data.rel", false)
     99         .Case(".bss", false)
    100         .Default(true);
    101       EmitThisSym = true;
    102       break;
    103     case ELF::R_ARM_ABS32:
    104       // But things get strange with R_ARM_ABS32
    105       // In this case, most things that go in .rodata show up
    106       // as section relative relocations
    107       InNormalSection =
    108         StringSwitch<bool>(Section.getSectionName())
    109         .Case(".data.rel.ro.local", false)
    110         .Case(".data.rel", false)
    111         .Case(".rodata", false)
    112         .Case(".bss", false)
    113         .Default(true);
    114       EmitThisSym = false;
    115       break;
    116     }
    117   } else {
    118     NonPCRelCount++;
    119     InNormalSection =
    120       StringSwitch<bool>(Section.getSectionName())
    121       .Case(".data.rel.ro.local", false)
    122       .Case(".rodata", false)
    123       .Case(".data.rel", false)
    124       .Case(".bss", false)
    125       .Default(true);
    126 
    127     switch (RelocType) {
    128     default: EmitThisSym = true; break;
    129     case ELF::R_ARM_ABS32: EmitThisSym = false; break;
    130     case ELF::R_ARM_PREL31: EmitThisSym = false; break;
    131     }
    132   }
    133 
    134   if (EmitThisSym)
    135     return &Symbol;
    136   if (! Symbol.isTemporary() && InNormalSection) {
    137     return &Symbol;
    138   }
    139   return NULL;
    140 }
    141 
    142 // Need to examine the Fixup when determining whether to
    143 // emit the relocation as an explicit symbol or as a section relative
    144 // offset
    145 unsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target,
    146                                           const MCFixup &Fixup,
    147                                           bool IsPCRel,
    148                                           bool IsRelocWithSymbol,
    149                                           int64_t Addend) const {
    150   return GetRelocTypeInner(Target, Fixup, IsPCRel);
    151 }
    152 
    153 unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
    154                                                const MCFixup &Fixup,
    155                                                bool IsPCRel) const  {
    156   MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ?
    157     MCSymbolRefExpr::VK_None : Target.getSymA()->getKind();
    158 
    159   unsigned Type = 0;
    160   if (IsPCRel) {
    161     switch ((unsigned)Fixup.getKind()) {
    162     default: llvm_unreachable("Unimplemented");
    163     case FK_Data_4:
    164       switch (Modifier) {
    165       default: llvm_unreachable("Unsupported Modifier");
    166       case MCSymbolRefExpr::VK_None:
    167         Type = ELF::R_ARM_REL32;
    168         break;
    169       case MCSymbolRefExpr::VK_ARM_TLSGD:
    170         llvm_unreachable("unimplemented");
    171       case MCSymbolRefExpr::VK_ARM_GOTTPOFF:
    172         Type = ELF::R_ARM_TLS_IE32;
    173         break;
    174       }
    175       break;
    176     case ARM::fixup_arm_blx:
    177     case ARM::fixup_arm_uncondbl:
    178       switch (Modifier) {
    179       case MCSymbolRefExpr::VK_ARM_PLT:
    180         Type = ELF::R_ARM_PLT32;
    181         break;
    182       default:
    183         Type = ELF::R_ARM_CALL;
    184         break;
    185       }
    186       break;
    187     case ARM::fixup_arm_condbl:
    188     case ARM::fixup_arm_condbranch:
    189     case ARM::fixup_arm_uncondbranch:
    190       Type = ELF::R_ARM_JUMP24;
    191       break;
    192     case ARM::fixup_t2_condbranch:
    193     case ARM::fixup_t2_uncondbranch:
    194       Type = ELF::R_ARM_THM_JUMP24;
    195       break;
    196     case ARM::fixup_arm_movt_hi16:
    197     case ARM::fixup_arm_movt_hi16_pcrel:
    198       Type = ELF::R_ARM_MOVT_PREL;
    199       break;
    200     case ARM::fixup_arm_movw_lo16:
    201     case ARM::fixup_arm_movw_lo16_pcrel:
    202       Type = ELF::R_ARM_MOVW_PREL_NC;
    203       break;
    204     case ARM::fixup_t2_movt_hi16:
    205     case ARM::fixup_t2_movt_hi16_pcrel:
    206       Type = ELF::R_ARM_THM_MOVT_PREL;
    207       break;
    208     case ARM::fixup_t2_movw_lo16:
    209     case ARM::fixup_t2_movw_lo16_pcrel:
    210       Type = ELF::R_ARM_THM_MOVW_PREL_NC;
    211       break;
    212     case ARM::fixup_arm_thumb_bl:
    213     case ARM::fixup_arm_thumb_blx:
    214       Type = ELF::R_ARM_THM_CALL;
    215       break;
    216     }
    217   } else {
    218     switch ((unsigned)Fixup.getKind()) {
    219     default: llvm_unreachable("invalid fixup kind!");
    220     case FK_Data_4:
    221       switch (Modifier) {
    222       default: llvm_unreachable("Unsupported Modifier");
    223       case MCSymbolRefExpr::VK_ARM_NONE:
    224         Type = ELF::R_ARM_NONE;
    225         break;
    226       case MCSymbolRefExpr::VK_ARM_GOT:
    227         Type = ELF::R_ARM_GOT_BREL;
    228         break;
    229       case MCSymbolRefExpr::VK_ARM_TLSGD:
    230         Type = ELF::R_ARM_TLS_GD32;
    231         break;
    232       case MCSymbolRefExpr::VK_ARM_TPOFF:
    233         Type = ELF::R_ARM_TLS_LE32;
    234         break;
    235       case MCSymbolRefExpr::VK_ARM_GOTTPOFF:
    236         Type = ELF::R_ARM_TLS_IE32;
    237         break;
    238       case MCSymbolRefExpr::VK_None:
    239         Type = ELF::R_ARM_ABS32;
    240         break;
    241       case MCSymbolRefExpr::VK_ARM_GOTOFF:
    242         Type = ELF::R_ARM_GOTOFF32;
    243         break;
    244       case MCSymbolRefExpr::VK_ARM_TARGET1:
    245         Type = ELF::R_ARM_TARGET1;
    246         break;
    247       case MCSymbolRefExpr::VK_ARM_TARGET2:
    248         Type = ELF::R_ARM_TARGET2;
    249         break;
    250       case MCSymbolRefExpr::VK_ARM_PREL31:
    251         Type = ELF::R_ARM_PREL31;
    252         break;
    253       }
    254       break;
    255     case ARM::fixup_arm_ldst_pcrel_12:
    256     case ARM::fixup_arm_pcrel_10:
    257     case ARM::fixup_arm_adr_pcrel_12:
    258     case ARM::fixup_arm_thumb_bl:
    259     case ARM::fixup_arm_thumb_cb:
    260     case ARM::fixup_arm_thumb_cp:
    261     case ARM::fixup_arm_thumb_br:
    262       llvm_unreachable("Unimplemented");
    263     case ARM::fixup_arm_condbranch:
    264     case ARM::fixup_arm_uncondbranch:
    265       Type = ELF::R_ARM_JUMP24;
    266       break;
    267     case ARM::fixup_arm_movt_hi16:
    268       Type = ELF::R_ARM_MOVT_ABS;
    269       break;
    270     case ARM::fixup_arm_movw_lo16:
    271       Type = ELF::R_ARM_MOVW_ABS_NC;
    272       break;
    273     case ARM::fixup_t2_movt_hi16:
    274       Type = ELF::R_ARM_THM_MOVT_ABS;
    275       break;
    276     case ARM::fixup_t2_movw_lo16:
    277       Type = ELF::R_ARM_THM_MOVW_ABS_NC;
    278       break;
    279     }
    280   }
    281 
    282   return Type;
    283 }
    284 
    285 MCObjectWriter *llvm::createARMELFObjectWriter(raw_ostream &OS,
    286                                                uint8_t OSABI) {
    287   MCELFObjectTargetWriter *MOTW = new ARMELFObjectWriter(OSABI);
    288   return createELFObjectWriter(MOTW, OS,  /*IsLittleEndian=*/true);
    289 }
    290