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