ARMELFObjectWriter.cpp revision 234285
1234285Sdim//===-- ARMELFObjectWriter.cpp - ARM ELF Writer ---------------------------===// 2234285Sdim// 3234285Sdim// The LLVM Compiler Infrastructure 4234285Sdim// 5234285Sdim// This file is distributed under the University of Illinois Open Source 6234285Sdim// License. See LICENSE.TXT for details. 7234285Sdim// 8234285Sdim//===----------------------------------------------------------------------===// 9234285Sdim 10234285Sdim#include "MCTargetDesc/ARMFixupKinds.h" 11234285Sdim#include "MCTargetDesc/ARMMCTargetDesc.h" 12234285Sdim#include "llvm/Support/Debug.h" 13234285Sdim#include "llvm/Support/ErrorHandling.h" 14234285Sdim#include "llvm/Support/raw_ostream.h" 15234285Sdim#include "llvm/ADT/Statistic.h" 16234285Sdim#include "llvm/ADT/StringSwitch.h" 17234285Sdim#include "llvm/MC/MCELFObjectWriter.h" 18234285Sdim#include "llvm/MC/MCExpr.h" 19234285Sdim#include "llvm/MC/MCSectionELF.h" 20234285Sdim#include "llvm/MC/MCValue.h" 21234285Sdim 22234285Sdimusing namespace llvm; 23234285Sdim 24234285Sdimnamespace { 25234285Sdim class ARMELFObjectWriter : public MCELFObjectTargetWriter { 26234285Sdim enum { DefaultEABIVersion = 0x05000000U }; 27234285Sdim unsigned GetRelocTypeInner(const MCValue &Target, 28234285Sdim const MCFixup &Fixup, 29234285Sdim bool IsPCRel) const; 30234285Sdim 31234285Sdim 32234285Sdim public: 33234285Sdim ARMELFObjectWriter(uint8_t OSABI); 34234285Sdim 35234285Sdim virtual ~ARMELFObjectWriter(); 36234285Sdim 37234285Sdim virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, 38234285Sdim bool IsPCRel, bool IsRelocWithSymbol, 39234285Sdim int64_t Addend) const; 40234285Sdim virtual unsigned getEFlags() const; 41234285Sdim virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, 42234285Sdim const MCValue &Target, 43234285Sdim const MCFragment &F, 44234285Sdim const MCFixup &Fixup, 45234285Sdim bool IsPCRel) const; 46234285Sdim }; 47234285Sdim} 48234285Sdim 49234285SdimARMELFObjectWriter::ARMELFObjectWriter(uint8_t OSABI) 50234285Sdim : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI, 51234285Sdim ELF::EM_ARM, 52234285Sdim /*HasRelocationAddend*/ false) {} 53234285Sdim 54234285SdimARMELFObjectWriter::~ARMELFObjectWriter() {} 55234285Sdim 56234285Sdim// FIXME: get the real EABI Version from the Triple. 57234285Sdimunsigned ARMELFObjectWriter::getEFlags() const { 58234285Sdim return ELF::EF_ARM_EABIMASK & DefaultEABIVersion; 59234285Sdim} 60234285Sdim 61234285Sdim// In ARM, _MergedGlobals and other most symbols get emitted directly. 62234285Sdim// I.e. not as an offset to a section symbol. 63234285Sdim// This code is an approximation of what ARM/gcc does. 64234285Sdim 65234285SdimSTATISTIC(PCRelCount, "Total number of PIC Relocations"); 66234285SdimSTATISTIC(NonPCRelCount, "Total number of non-PIC relocations"); 67234285Sdim 68234285Sdimconst MCSymbol *ARMELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm, 69234285Sdim const MCValue &Target, 70234285Sdim const MCFragment &F, 71234285Sdim const MCFixup &Fixup, 72234285Sdim bool IsPCRel) const { 73234285Sdim const MCSymbol &Symbol = Target.getSymA()->getSymbol().AliasedSymbol(); 74234285Sdim bool EmitThisSym = false; 75234285Sdim 76234285Sdim const MCSectionELF &Section = 77234285Sdim static_cast<const MCSectionELF&>(Symbol.getSection()); 78234285Sdim bool InNormalSection = true; 79234285Sdim unsigned RelocType = 0; 80234285Sdim RelocType = GetRelocTypeInner(Target, Fixup, IsPCRel); 81234285Sdim 82234285Sdim DEBUG( 83234285Sdim const MCSymbolRefExpr::VariantKind Kind = Target.getSymA()->getKind(); 84234285Sdim MCSymbolRefExpr::VariantKind Kind2; 85234285Sdim Kind2 = Target.getSymB() ? Target.getSymB()->getKind() : 86234285Sdim MCSymbolRefExpr::VK_None; 87234285Sdim dbgs() << "considering symbol " 88234285Sdim << Section.getSectionName() << "/" 89234285Sdim << Symbol.getName() << "/" 90234285Sdim << " Rel:" << (unsigned)RelocType 91234285Sdim << " Kind: " << (int)Kind << "/" << (int)Kind2 92234285Sdim << " Tmp:" 93234285Sdim << Symbol.isAbsolute() << "/" << Symbol.isDefined() << "/" 94234285Sdim << Symbol.isVariable() << "/" << Symbol.isTemporary() 95234285Sdim << " Counts:" << PCRelCount << "/" << NonPCRelCount << "\n"); 96234285Sdim 97234285Sdim if (IsPCRel) { ++PCRelCount; 98234285Sdim switch (RelocType) { 99234285Sdim default: 100234285Sdim // Most relocation types are emitted as explicit symbols 101234285Sdim InNormalSection = 102234285Sdim StringSwitch<bool>(Section.getSectionName()) 103234285Sdim .Case(".data.rel.ro.local", false) 104234285Sdim .Case(".data.rel", false) 105234285Sdim .Case(".bss", false) 106234285Sdim .Default(true); 107234285Sdim EmitThisSym = true; 108234285Sdim break; 109234285Sdim case ELF::R_ARM_ABS32: 110234285Sdim // But things get strange with R_ARM_ABS32 111234285Sdim // In this case, most things that go in .rodata show up 112234285Sdim // as section relative relocations 113234285Sdim InNormalSection = 114234285Sdim StringSwitch<bool>(Section.getSectionName()) 115234285Sdim .Case(".data.rel.ro.local", false) 116234285Sdim .Case(".data.rel", false) 117234285Sdim .Case(".rodata", false) 118234285Sdim .Case(".bss", false) 119234285Sdim .Default(true); 120234285Sdim EmitThisSym = false; 121234285Sdim break; 122234285Sdim } 123234285Sdim } else { 124234285Sdim NonPCRelCount++; 125234285Sdim InNormalSection = 126234285Sdim StringSwitch<bool>(Section.getSectionName()) 127234285Sdim .Case(".data.rel.ro.local", false) 128234285Sdim .Case(".rodata", false) 129234285Sdim .Case(".data.rel", false) 130234285Sdim .Case(".bss", false) 131234285Sdim .Default(true); 132234285Sdim 133234285Sdim switch (RelocType) { 134234285Sdim default: EmitThisSym = true; break; 135234285Sdim case ELF::R_ARM_ABS32: EmitThisSym = false; break; 136234285Sdim } 137234285Sdim } 138234285Sdim 139234285Sdim if (EmitThisSym) 140234285Sdim return &Symbol; 141234285Sdim if (! Symbol.isTemporary() && InNormalSection) { 142234285Sdim return &Symbol; 143234285Sdim } 144234285Sdim return NULL; 145234285Sdim} 146234285Sdim 147234285Sdim// Need to examine the Fixup when determining whether to 148234285Sdim// emit the relocation as an explicit symbol or as a section relative 149234285Sdim// offset 150234285Sdimunsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target, 151234285Sdim const MCFixup &Fixup, 152234285Sdim bool IsPCRel, 153234285Sdim bool IsRelocWithSymbol, 154234285Sdim int64_t Addend) const { 155234285Sdim return GetRelocTypeInner(Target, Fixup, IsPCRel); 156234285Sdim} 157234285Sdim 158234285Sdimunsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target, 159234285Sdim const MCFixup &Fixup, 160234285Sdim bool IsPCRel) const { 161234285Sdim MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? 162234285Sdim MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); 163234285Sdim 164234285Sdim unsigned Type = 0; 165234285Sdim if (IsPCRel) { 166234285Sdim switch ((unsigned)Fixup.getKind()) { 167234285Sdim default: llvm_unreachable("Unimplemented"); 168234285Sdim case FK_Data_4: 169234285Sdim switch (Modifier) { 170234285Sdim default: llvm_unreachable("Unsupported Modifier"); 171234285Sdim case MCSymbolRefExpr::VK_None: 172234285Sdim Type = ELF::R_ARM_REL32; 173234285Sdim break; 174234285Sdim case MCSymbolRefExpr::VK_ARM_TLSGD: 175234285Sdim llvm_unreachable("unimplemented"); 176234285Sdim case MCSymbolRefExpr::VK_ARM_GOTTPOFF: 177234285Sdim Type = ELF::R_ARM_TLS_IE32; 178234285Sdim break; 179234285Sdim } 180234285Sdim break; 181234285Sdim case ARM::fixup_arm_uncondbl: 182234285Sdim case ARM::fixup_arm_blx: 183234285Sdim case ARM::fixup_arm_uncondbranch: 184234285Sdim switch (Modifier) { 185234285Sdim case MCSymbolRefExpr::VK_ARM_PLT: 186234285Sdim Type = ELF::R_ARM_PLT32; 187234285Sdim break; 188234285Sdim default: 189234285Sdim Type = ELF::R_ARM_CALL; 190234285Sdim break; 191234285Sdim } 192234285Sdim break; 193234285Sdim case ARM::fixup_arm_condbl: 194234285Sdim case ARM::fixup_arm_condbranch: 195234285Sdim Type = ELF::R_ARM_JUMP24; 196234285Sdim break; 197234285Sdim case ARM::fixup_arm_movt_hi16: 198234285Sdim case ARM::fixup_arm_movt_hi16_pcrel: 199234285Sdim Type = ELF::R_ARM_MOVT_PREL; 200234285Sdim break; 201234285Sdim case ARM::fixup_arm_movw_lo16: 202234285Sdim case ARM::fixup_arm_movw_lo16_pcrel: 203234285Sdim Type = ELF::R_ARM_MOVW_PREL_NC; 204234285Sdim break; 205234285Sdim case ARM::fixup_t2_movt_hi16: 206234285Sdim case ARM::fixup_t2_movt_hi16_pcrel: 207234285Sdim Type = ELF::R_ARM_THM_MOVT_PREL; 208234285Sdim break; 209234285Sdim case ARM::fixup_t2_movw_lo16: 210234285Sdim case ARM::fixup_t2_movw_lo16_pcrel: 211234285Sdim Type = ELF::R_ARM_THM_MOVW_PREL_NC; 212234285Sdim break; 213234285Sdim case ARM::fixup_arm_thumb_bl: 214234285Sdim case ARM::fixup_arm_thumb_blx: 215234285Sdim Type = ELF::R_ARM_THM_CALL; 216234285Sdim break; 217234285Sdim } 218234285Sdim } else { 219234285Sdim switch ((unsigned)Fixup.getKind()) { 220234285Sdim default: llvm_unreachable("invalid fixup kind!"); 221234285Sdim case FK_Data_4: 222234285Sdim switch (Modifier) { 223234285Sdim default: llvm_unreachable("Unsupported Modifier"); 224234285Sdim case MCSymbolRefExpr::VK_ARM_GOT: 225234285Sdim Type = ELF::R_ARM_GOT_BREL; 226234285Sdim break; 227234285Sdim case MCSymbolRefExpr::VK_ARM_TLSGD: 228234285Sdim Type = ELF::R_ARM_TLS_GD32; 229234285Sdim break; 230234285Sdim case MCSymbolRefExpr::VK_ARM_TPOFF: 231234285Sdim Type = ELF::R_ARM_TLS_LE32; 232234285Sdim break; 233234285Sdim case MCSymbolRefExpr::VK_ARM_GOTTPOFF: 234234285Sdim Type = ELF::R_ARM_TLS_IE32; 235234285Sdim break; 236234285Sdim case MCSymbolRefExpr::VK_None: 237234285Sdim Type = ELF::R_ARM_ABS32; 238234285Sdim break; 239234285Sdim case MCSymbolRefExpr::VK_ARM_GOTOFF: 240234285Sdim Type = ELF::R_ARM_GOTOFF32; 241234285Sdim break; 242234285Sdim case MCSymbolRefExpr::VK_ARM_TARGET1: 243234285Sdim Type = ELF::R_ARM_TARGET1; 244234285Sdim break; 245234285Sdim } 246234285Sdim break; 247234285Sdim case ARM::fixup_arm_ldst_pcrel_12: 248234285Sdim case ARM::fixup_arm_pcrel_10: 249234285Sdim case ARM::fixup_arm_adr_pcrel_12: 250234285Sdim case ARM::fixup_arm_thumb_bl: 251234285Sdim case ARM::fixup_arm_thumb_cb: 252234285Sdim case ARM::fixup_arm_thumb_cp: 253234285Sdim case ARM::fixup_arm_thumb_br: 254234285Sdim llvm_unreachable("Unimplemented"); 255234285Sdim case ARM::fixup_arm_uncondbranch: 256234285Sdim Type = ELF::R_ARM_CALL; 257234285Sdim break; 258234285Sdim case ARM::fixup_arm_condbranch: 259234285Sdim Type = ELF::R_ARM_JUMP24; 260234285Sdim break; 261234285Sdim case ARM::fixup_arm_movt_hi16: 262234285Sdim Type = ELF::R_ARM_MOVT_ABS; 263234285Sdim break; 264234285Sdim case ARM::fixup_arm_movw_lo16: 265234285Sdim Type = ELF::R_ARM_MOVW_ABS_NC; 266234285Sdim break; 267234285Sdim case ARM::fixup_t2_movt_hi16: 268234285Sdim Type = ELF::R_ARM_THM_MOVT_ABS; 269234285Sdim break; 270234285Sdim case ARM::fixup_t2_movw_lo16: 271234285Sdim Type = ELF::R_ARM_THM_MOVW_ABS_NC; 272234285Sdim break; 273234285Sdim } 274234285Sdim } 275234285Sdim 276234285Sdim return Type; 277234285Sdim} 278234285Sdim 279234285SdimMCObjectWriter *llvm::createARMELFObjectWriter(raw_ostream &OS, 280234285Sdim uint8_t OSABI) { 281234285Sdim MCELFObjectTargetWriter *MOTW = new ARMELFObjectWriter(OSABI); 282234285Sdim return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/true); 283234285Sdim} 284