1 //===-- PPCELFObjectWriter.cpp - PPC 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/PPCMCTargetDesc.h" 11 #include "MCTargetDesc/PPCFixupKinds.h" 12 #include "llvm/ADT/STLExtras.h" 13 #include "llvm/MC/MCELFObjectWriter.h" 14 #include "llvm/MC/MCExpr.h" 15 #include "llvm/MC/MCValue.h" 16 #include "llvm/Support/ErrorHandling.h" 17 18 using namespace llvm; 19 20 namespace { 21 class PPCELFObjectWriter : public MCELFObjectTargetWriter { 22 public: 23 PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI); 24 25 virtual ~PPCELFObjectWriter(); 26 protected: 27 virtual unsigned getRelocTypeInner(const MCValue &Target, 28 const MCFixup &Fixup, 29 bool IsPCRel) const; 30 virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, 31 bool IsPCRel, bool IsRelocWithSymbol, 32 int64_t Addend) const; 33 virtual const MCSymbol *undefinedExplicitRelSym(const MCValue &Target, 34 const MCFixup &Fixup, 35 bool IsPCRel) const; 36 }; 37 } 38 39 PPCELFObjectWriter::PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI) 40 : MCELFObjectTargetWriter(Is64Bit, OSABI, 41 Is64Bit ? ELF::EM_PPC64 : ELF::EM_PPC, 42 /*HasRelocationAddend*/ true) {} 43 44 PPCELFObjectWriter::~PPCELFObjectWriter() { 45 } 46 47 unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target, 48 const MCFixup &Fixup, 49 bool IsPCRel) const 50 { 51 MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? 52 MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); 53 54 // determine the type of the relocation 55 unsigned Type; 56 if (IsPCRel) { 57 switch ((unsigned)Fixup.getKind()) { 58 default: 59 llvm_unreachable("Unimplemented"); 60 case PPC::fixup_ppc_br24: 61 Type = ELF::R_PPC_REL24; 62 break; 63 case PPC::fixup_ppc_brcond14: 64 Type = ELF::R_PPC_REL14; 65 break; 66 case FK_Data_4: 67 case FK_PCRel_4: 68 Type = ELF::R_PPC_REL32; 69 break; 70 case FK_Data_8: 71 case FK_PCRel_8: 72 Type = ELF::R_PPC64_REL64; 73 break; 74 } 75 } else { 76 switch ((unsigned)Fixup.getKind()) { 77 default: llvm_unreachable("invalid fixup kind!"); 78 case PPC::fixup_ppc_br24: 79 Type = ELF::R_PPC_ADDR24; 80 break; 81 case PPC::fixup_ppc_brcond14: 82 Type = ELF::R_PPC_ADDR14; // XXX: or BRNTAKEN?_ 83 break; 84 case PPC::fixup_ppc_ha16: 85 case PPC::fixup_ppc_lo16: 86 switch (Modifier) { 87 default: llvm_unreachable("Unsupported Modifier"); 88 case MCSymbolRefExpr::VK_PPC_TPREL16_HA: 89 Type = ELF::R_PPC_TPREL16_HA; 90 break; 91 case MCSymbolRefExpr::VK_PPC_DTPREL16_HA: 92 Type = ELF::R_PPC64_DTPREL16_HA; 93 break; 94 case MCSymbolRefExpr::VK_PPC_GAS_HA16: 95 case MCSymbolRefExpr::VK_PPC_DARWIN_HA16: 96 Type = ELF::R_PPC_ADDR16_HA; 97 break; 98 case MCSymbolRefExpr::VK_PPC_TOC16_HA: 99 Type = ELF::R_PPC64_TOC16_HA; 100 break; 101 case MCSymbolRefExpr::VK_PPC_GOT_TPREL16_HA: 102 Type = ELF::R_PPC64_GOT_TPREL16_HA; 103 break; 104 case MCSymbolRefExpr::VK_PPC_GOT_TLSGD16_HA: 105 Type = ELF::R_PPC64_GOT_TLSGD16_HA; 106 break; 107 case MCSymbolRefExpr::VK_PPC_GOT_TLSLD16_HA: 108 Type = ELF::R_PPC64_GOT_TLSLD16_HA; 109 break; 110 case MCSymbolRefExpr::VK_PPC_TPREL16_LO: 111 Type = ELF::R_PPC_TPREL16_LO; 112 break; 113 case MCSymbolRefExpr::VK_PPC_DTPREL16_LO: 114 Type = ELF::R_PPC64_DTPREL16_LO; 115 break; 116 case MCSymbolRefExpr::VK_None: 117 Type = ELF::R_PPC_ADDR16; 118 break; 119 case MCSymbolRefExpr::VK_PPC_GAS_LO16: 120 case MCSymbolRefExpr::VK_PPC_DARWIN_LO16: 121 Type = ELF::R_PPC_ADDR16_LO; 122 break; 123 case MCSymbolRefExpr::VK_PPC_TOC_ENTRY: 124 Type = ELF::R_PPC64_TOC16; 125 break; 126 case MCSymbolRefExpr::VK_PPC_TOC16_LO: 127 Type = ELF::R_PPC64_TOC16_LO; 128 break; 129 case MCSymbolRefExpr::VK_PPC_GOT_TLSGD16_LO: 130 Type = ELF::R_PPC64_GOT_TLSGD16_LO; 131 break; 132 case MCSymbolRefExpr::VK_PPC_GOT_TLSLD16_LO: 133 Type = ELF::R_PPC64_GOT_TLSLD16_LO; 134 break; 135 } 136 break; 137 case PPC::fixup_ppc_lo16_ds: 138 switch (Modifier) { 139 default: llvm_unreachable("Unsupported Modifier"); 140 case MCSymbolRefExpr::VK_None: 141 Type = ELF::R_PPC64_ADDR16_DS; 142 break; 143 case MCSymbolRefExpr::VK_PPC_GAS_LO16: 144 case MCSymbolRefExpr::VK_PPC_DARWIN_LO16: 145 Type = ELF::R_PPC64_ADDR16_LO_DS; 146 break; 147 case MCSymbolRefExpr::VK_PPC_TOC_ENTRY: 148 Type = ELF::R_PPC64_TOC16_DS; 149 break; 150 case MCSymbolRefExpr::VK_PPC_TOC16_LO: 151 Type = ELF::R_PPC64_TOC16_LO_DS; 152 break; 153 case MCSymbolRefExpr::VK_PPC_GOT_TPREL16_LO: 154 Type = ELF::R_PPC64_GOT_TPREL16_LO_DS; 155 break; 156 } 157 break; 158 case PPC::fixup_ppc_tlsreg: 159 Type = ELF::R_PPC64_TLS; 160 break; 161 case PPC::fixup_ppc_nofixup: 162 switch (Modifier) { 163 default: llvm_unreachable("Unsupported Modifier"); 164 case MCSymbolRefExpr::VK_PPC_TLSGD: 165 Type = ELF::R_PPC64_TLSGD; 166 break; 167 case MCSymbolRefExpr::VK_PPC_TLSLD: 168 Type = ELF::R_PPC64_TLSLD; 169 break; 170 } 171 break; 172 case FK_Data_8: 173 switch (Modifier) { 174 default: llvm_unreachable("Unsupported Modifier"); 175 case MCSymbolRefExpr::VK_PPC_TOC: 176 Type = ELF::R_PPC64_TOC; 177 break; 178 case MCSymbolRefExpr::VK_None: 179 Type = ELF::R_PPC64_ADDR64; 180 break; 181 } 182 break; 183 case FK_Data_4: 184 Type = ELF::R_PPC_ADDR32; 185 break; 186 case FK_Data_2: 187 Type = ELF::R_PPC_ADDR16; 188 break; 189 } 190 } 191 return Type; 192 } 193 194 unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target, 195 const MCFixup &Fixup, 196 bool IsPCRel, 197 bool IsRelocWithSymbol, 198 int64_t Addend) const { 199 return getRelocTypeInner(Target, Fixup, IsPCRel); 200 } 201 202 const MCSymbol *PPCELFObjectWriter::undefinedExplicitRelSym(const MCValue &Target, 203 const MCFixup &Fixup, 204 bool IsPCRel) const { 205 assert(Target.getSymA() && "SymA cannot be 0"); 206 const MCSymbol &Symbol = Target.getSymA()->getSymbol().AliasedSymbol(); 207 208 unsigned RelocType = getRelocTypeInner(Target, Fixup, IsPCRel); 209 210 // The .odp creation emits a relocation against the symbol ".TOC." which 211 // create a R_PPC64_TOC relocation. However the relocation symbol name 212 // in final object creation should be NULL, since the symbol does not 213 // really exist, it is just the reference to TOC base for the current 214 // object file. 215 bool EmitThisSym = RelocType != ELF::R_PPC64_TOC; 216 217 if (EmitThisSym && !Symbol.isTemporary()) 218 return &Symbol; 219 return NULL; 220 } 221 222 MCObjectWriter *llvm::createPPCELFObjectWriter(raw_ostream &OS, 223 bool Is64Bit, 224 uint8_t OSABI) { 225 MCELFObjectTargetWriter *MOTW = new PPCELFObjectWriter(Is64Bit, OSABI); 226 return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false); 227 } 228