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 10252723Sdim#include "MCTargetDesc/ARMMCTargetDesc.h" 11234285Sdim#include "MCTargetDesc/ARMFixupKinds.h" 12234285Sdim#include "llvm/ADT/Statistic.h" 13234285Sdim#include "llvm/ADT/StringSwitch.h" 14234285Sdim#include "llvm/MC/MCELFObjectWriter.h" 15234285Sdim#include "llvm/MC/MCExpr.h" 16234285Sdim#include "llvm/MC/MCSectionELF.h" 17234285Sdim#include "llvm/MC/MCValue.h" 18252723Sdim#include "llvm/Support/Debug.h" 19252723Sdim#include "llvm/Support/ErrorHandling.h" 20252723Sdim#include "llvm/Support/raw_ostream.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 const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, 41234285Sdim const MCValue &Target, 42234285Sdim const MCFragment &F, 43234285Sdim const MCFixup &Fixup, 44234285Sdim bool IsPCRel) const; 45234285Sdim }; 46234285Sdim} 47234285Sdim 48234285SdimARMELFObjectWriter::ARMELFObjectWriter(uint8_t OSABI) 49234285Sdim : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSABI, 50234285Sdim ELF::EM_ARM, 51234285Sdim /*HasRelocationAddend*/ false) {} 52234285Sdim 53234285SdimARMELFObjectWriter::~ARMELFObjectWriter() {} 54234285Sdim 55234285Sdim// In ARM, _MergedGlobals and other most symbols get emitted directly. 56234285Sdim// I.e. not as an offset to a section symbol. 57234285Sdim// This code is an approximation of what ARM/gcc does. 58234285Sdim 59234285SdimSTATISTIC(PCRelCount, "Total number of PIC Relocations"); 60234285SdimSTATISTIC(NonPCRelCount, "Total number of non-PIC relocations"); 61234285Sdim 62234285Sdimconst MCSymbol *ARMELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm, 63234285Sdim const MCValue &Target, 64234285Sdim const MCFragment &F, 65234285Sdim const MCFixup &Fixup, 66234285Sdim bool IsPCRel) const { 67234285Sdim const MCSymbol &Symbol = Target.getSymA()->getSymbol().AliasedSymbol(); 68234285Sdim bool EmitThisSym = false; 69234285Sdim 70234285Sdim const MCSectionELF &Section = 71234285Sdim static_cast<const MCSectionELF&>(Symbol.getSection()); 72234285Sdim bool InNormalSection = true; 73234285Sdim unsigned RelocType = 0; 74234285Sdim RelocType = GetRelocTypeInner(Target, Fixup, IsPCRel); 75234285Sdim 76234285Sdim DEBUG( 77234285Sdim const MCSymbolRefExpr::VariantKind Kind = Target.getSymA()->getKind(); 78234285Sdim MCSymbolRefExpr::VariantKind Kind2; 79234285Sdim Kind2 = Target.getSymB() ? Target.getSymB()->getKind() : 80234285Sdim MCSymbolRefExpr::VK_None; 81234285Sdim dbgs() << "considering symbol " 82234285Sdim << Section.getSectionName() << "/" 83234285Sdim << Symbol.getName() << "/" 84234285Sdim << " Rel:" << (unsigned)RelocType 85234285Sdim << " Kind: " << (int)Kind << "/" << (int)Kind2 86234285Sdim << " Tmp:" 87234285Sdim << Symbol.isAbsolute() << "/" << Symbol.isDefined() << "/" 88234285Sdim << Symbol.isVariable() << "/" << Symbol.isTemporary() 89234285Sdim << " Counts:" << PCRelCount << "/" << NonPCRelCount << "\n"); 90234285Sdim 91234285Sdim if (IsPCRel) { ++PCRelCount; 92234285Sdim switch (RelocType) { 93234285Sdim default: 94234285Sdim // Most relocation types are emitted as explicit symbols 95234285Sdim InNormalSection = 96234285Sdim StringSwitch<bool>(Section.getSectionName()) 97234285Sdim .Case(".data.rel.ro.local", false) 98234285Sdim .Case(".data.rel", false) 99234285Sdim .Case(".bss", false) 100234285Sdim .Default(true); 101234285Sdim EmitThisSym = true; 102234285Sdim break; 103234285Sdim case ELF::R_ARM_ABS32: 104234285Sdim // But things get strange with R_ARM_ABS32 105234285Sdim // In this case, most things that go in .rodata show up 106234285Sdim // as section relative relocations 107234285Sdim InNormalSection = 108234285Sdim StringSwitch<bool>(Section.getSectionName()) 109234285Sdim .Case(".data.rel.ro.local", false) 110234285Sdim .Case(".data.rel", false) 111234285Sdim .Case(".rodata", false) 112234285Sdim .Case(".bss", false) 113234285Sdim .Default(true); 114234285Sdim EmitThisSym = false; 115234285Sdim break; 116234285Sdim } 117234285Sdim } else { 118234285Sdim NonPCRelCount++; 119234285Sdim InNormalSection = 120234285Sdim StringSwitch<bool>(Section.getSectionName()) 121234285Sdim .Case(".data.rel.ro.local", false) 122234285Sdim .Case(".rodata", false) 123234285Sdim .Case(".data.rel", false) 124234285Sdim .Case(".bss", false) 125234285Sdim .Default(true); 126234285Sdim 127234285Sdim switch (RelocType) { 128234285Sdim default: EmitThisSym = true; break; 129234285Sdim case ELF::R_ARM_ABS32: EmitThisSym = false; break; 130252723Sdim case ELF::R_ARM_PREL31: EmitThisSym = false; break; 131234285Sdim } 132234285Sdim } 133234285Sdim 134234285Sdim if (EmitThisSym) 135234285Sdim return &Symbol; 136234285Sdim if (! Symbol.isTemporary() && InNormalSection) { 137234285Sdim return &Symbol; 138234285Sdim } 139234285Sdim return NULL; 140234285Sdim} 141234285Sdim 142234285Sdim// Need to examine the Fixup when determining whether to 143234285Sdim// emit the relocation as an explicit symbol or as a section relative 144234285Sdim// offset 145234285Sdimunsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target, 146234285Sdim const MCFixup &Fixup, 147234285Sdim bool IsPCRel, 148234285Sdim bool IsRelocWithSymbol, 149234285Sdim int64_t Addend) const { 150234285Sdim return GetRelocTypeInner(Target, Fixup, IsPCRel); 151234285Sdim} 152234285Sdim 153234285Sdimunsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target, 154234285Sdim const MCFixup &Fixup, 155234285Sdim bool IsPCRel) const { 156234285Sdim MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? 157234285Sdim MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); 158234285Sdim 159234285Sdim unsigned Type = 0; 160234285Sdim if (IsPCRel) { 161234285Sdim switch ((unsigned)Fixup.getKind()) { 162234285Sdim default: llvm_unreachable("Unimplemented"); 163234285Sdim case FK_Data_4: 164234285Sdim switch (Modifier) { 165234285Sdim default: llvm_unreachable("Unsupported Modifier"); 166234285Sdim case MCSymbolRefExpr::VK_None: 167234285Sdim Type = ELF::R_ARM_REL32; 168234285Sdim break; 169234285Sdim case MCSymbolRefExpr::VK_ARM_TLSGD: 170234285Sdim llvm_unreachable("unimplemented"); 171234285Sdim case MCSymbolRefExpr::VK_ARM_GOTTPOFF: 172234285Sdim Type = ELF::R_ARM_TLS_IE32; 173234285Sdim break; 174234285Sdim } 175234285Sdim break; 176245431Sdim case ARM::fixup_arm_blx: 177234285Sdim case ARM::fixup_arm_uncondbl: 178234285Sdim switch (Modifier) { 179234285Sdim case MCSymbolRefExpr::VK_ARM_PLT: 180234285Sdim Type = ELF::R_ARM_PLT32; 181234285Sdim break; 182234285Sdim default: 183234285Sdim Type = ELF::R_ARM_CALL; 184234285Sdim break; 185234285Sdim } 186234285Sdim break; 187234285Sdim case ARM::fixup_arm_condbl: 188234285Sdim case ARM::fixup_arm_condbranch: 189245431Sdim case ARM::fixup_arm_uncondbranch: 190234285Sdim Type = ELF::R_ARM_JUMP24; 191234285Sdim break; 192245431Sdim case ARM::fixup_t2_condbranch: 193245431Sdim case ARM::fixup_t2_uncondbranch: 194245431Sdim Type = ELF::R_ARM_THM_JUMP24; 195245431Sdim break; 196234285Sdim case ARM::fixup_arm_movt_hi16: 197234285Sdim case ARM::fixup_arm_movt_hi16_pcrel: 198234285Sdim Type = ELF::R_ARM_MOVT_PREL; 199234285Sdim break; 200234285Sdim case ARM::fixup_arm_movw_lo16: 201234285Sdim case ARM::fixup_arm_movw_lo16_pcrel: 202234285Sdim Type = ELF::R_ARM_MOVW_PREL_NC; 203234285Sdim break; 204234285Sdim case ARM::fixup_t2_movt_hi16: 205234285Sdim case ARM::fixup_t2_movt_hi16_pcrel: 206234285Sdim Type = ELF::R_ARM_THM_MOVT_PREL; 207234285Sdim break; 208234285Sdim case ARM::fixup_t2_movw_lo16: 209234285Sdim case ARM::fixup_t2_movw_lo16_pcrel: 210234285Sdim Type = ELF::R_ARM_THM_MOVW_PREL_NC; 211234285Sdim break; 212234285Sdim case ARM::fixup_arm_thumb_bl: 213234285Sdim case ARM::fixup_arm_thumb_blx: 214234285Sdim Type = ELF::R_ARM_THM_CALL; 215234285Sdim break; 216234285Sdim } 217234285Sdim } else { 218234285Sdim switch ((unsigned)Fixup.getKind()) { 219234285Sdim default: llvm_unreachable("invalid fixup kind!"); 220234285Sdim case FK_Data_4: 221234285Sdim switch (Modifier) { 222234285Sdim default: llvm_unreachable("Unsupported Modifier"); 223252723Sdim case MCSymbolRefExpr::VK_ARM_NONE: 224252723Sdim Type = ELF::R_ARM_NONE; 225252723Sdim break; 226234285Sdim case MCSymbolRefExpr::VK_ARM_GOT: 227234285Sdim Type = ELF::R_ARM_GOT_BREL; 228234285Sdim break; 229234285Sdim case MCSymbolRefExpr::VK_ARM_TLSGD: 230234285Sdim Type = ELF::R_ARM_TLS_GD32; 231234285Sdim break; 232234285Sdim case MCSymbolRefExpr::VK_ARM_TPOFF: 233234285Sdim Type = ELF::R_ARM_TLS_LE32; 234234285Sdim break; 235234285Sdim case MCSymbolRefExpr::VK_ARM_GOTTPOFF: 236234285Sdim Type = ELF::R_ARM_TLS_IE32; 237234285Sdim break; 238234285Sdim case MCSymbolRefExpr::VK_None: 239234285Sdim Type = ELF::R_ARM_ABS32; 240234285Sdim break; 241234285Sdim case MCSymbolRefExpr::VK_ARM_GOTOFF: 242234285Sdim Type = ELF::R_ARM_GOTOFF32; 243234285Sdim break; 244234285Sdim case MCSymbolRefExpr::VK_ARM_TARGET1: 245234285Sdim Type = ELF::R_ARM_TARGET1; 246234285Sdim break; 247245431Sdim case MCSymbolRefExpr::VK_ARM_TARGET2: 248245431Sdim Type = ELF::R_ARM_TARGET2; 249245431Sdim break; 250252723Sdim case MCSymbolRefExpr::VK_ARM_PREL31: 251252723Sdim Type = ELF::R_ARM_PREL31; 252252723Sdim break; 253252723Sdim } 254234285Sdim break; 255234285Sdim case ARM::fixup_arm_ldst_pcrel_12: 256234285Sdim case ARM::fixup_arm_pcrel_10: 257234285Sdim case ARM::fixup_arm_adr_pcrel_12: 258234285Sdim case ARM::fixup_arm_thumb_bl: 259234285Sdim case ARM::fixup_arm_thumb_cb: 260234285Sdim case ARM::fixup_arm_thumb_cp: 261234285Sdim case ARM::fixup_arm_thumb_br: 262234285Sdim llvm_unreachable("Unimplemented"); 263245431Sdim case ARM::fixup_arm_condbranch: 264234285Sdim case ARM::fixup_arm_uncondbranch: 265234285Sdim Type = ELF::R_ARM_JUMP24; 266234285Sdim break; 267234285Sdim case ARM::fixup_arm_movt_hi16: 268234285Sdim Type = ELF::R_ARM_MOVT_ABS; 269234285Sdim break; 270234285Sdim case ARM::fixup_arm_movw_lo16: 271234285Sdim Type = ELF::R_ARM_MOVW_ABS_NC; 272234285Sdim break; 273234285Sdim case ARM::fixup_t2_movt_hi16: 274234285Sdim Type = ELF::R_ARM_THM_MOVT_ABS; 275234285Sdim break; 276234285Sdim case ARM::fixup_t2_movw_lo16: 277234285Sdim Type = ELF::R_ARM_THM_MOVW_ABS_NC; 278234285Sdim break; 279234285Sdim } 280234285Sdim } 281234285Sdim 282234285Sdim return Type; 283234285Sdim} 284234285Sdim 285234285SdimMCObjectWriter *llvm::createARMELFObjectWriter(raw_ostream &OS, 286234285Sdim uint8_t OSABI) { 287234285Sdim MCELFObjectTargetWriter *MOTW = new ARMELFObjectWriter(OSABI); 288234285Sdim return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/true); 289234285Sdim} 290