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 virtual void sortRelocs(const MCAssembler &Asm, 38 std::vector<ELFRelocationEntry> &Relocs); 39 }; 40 41 class PPCELFRelocationEntry : public ELFRelocationEntry { 42 public: 43 PPCELFRelocationEntry(const ELFRelocationEntry &RE); 44 bool operator<(const PPCELFRelocationEntry &RE) const { 45 return (RE.r_offset < r_offset || 46 (RE.r_offset == r_offset && RE.Type > Type)); 47 } 48 }; 49 } 50 51 PPCELFRelocationEntry::PPCELFRelocationEntry(const ELFRelocationEntry &RE) 52 : ELFRelocationEntry(RE.r_offset, RE.Index, RE.Type, RE.Symbol, 53 RE.r_addend, *RE.Fixup) {} 54 55 PPCELFObjectWriter::PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI) 56 : MCELFObjectTargetWriter(Is64Bit, OSABI, 57 Is64Bit ? ELF::EM_PPC64 : ELF::EM_PPC, 58 /*HasRelocationAddend*/ true) {} 59 60 PPCELFObjectWriter::~PPCELFObjectWriter() { 61 } 62 63 unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target, 64 const MCFixup &Fixup, 65 bool IsPCRel) const 66 { 67 MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? 68 MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); 69 70 // determine the type of the relocation 71 unsigned Type; 72 if (IsPCRel) { 73 switch ((unsigned)Fixup.getKind()) { 74 default: 75 llvm_unreachable("Unimplemented"); 76 case PPC::fixup_ppc_br24: 77 Type = ELF::R_PPC_REL24; 78 break; 79 case PPC::fixup_ppc_brcond14: 80 Type = ELF::R_PPC_REL14; 81 break; 82 case FK_Data_4: 83 case FK_PCRel_4: 84 Type = ELF::R_PPC_REL32; 85 break; 86 case FK_Data_8: 87 case FK_PCRel_8: 88 Type = ELF::R_PPC64_REL64; 89 break; 90 } 91 } else { 92 switch ((unsigned)Fixup.getKind()) { 93 default: llvm_unreachable("invalid fixup kind!"); 94 case PPC::fixup_ppc_br24: 95 Type = ELF::R_PPC_ADDR24; 96 break; 97 case PPC::fixup_ppc_brcond14: 98 Type = ELF::R_PPC_ADDR14; // XXX: or BRNTAKEN?_ 99 break; 100 case PPC::fixup_ppc_ha16: 101 switch (Modifier) { 102 default: llvm_unreachable("Unsupported Modifier"); 103 case MCSymbolRefExpr::VK_PPC_TPREL16_HA: 104 Type = ELF::R_PPC_TPREL16_HA; 105 break; 106 case MCSymbolRefExpr::VK_PPC_DTPREL16_HA: 107 Type = ELF::R_PPC64_DTPREL16_HA; 108 break; 109 case MCSymbolRefExpr::VK_PPC_GAS_HA16: 110 case MCSymbolRefExpr::VK_PPC_DARWIN_HA16: 111 Type = ELF::R_PPC_ADDR16_HA; 112 break; 113 case MCSymbolRefExpr::VK_PPC_TOC16_HA: 114 Type = ELF::R_PPC64_TOC16_HA; 115 break; 116 case MCSymbolRefExpr::VK_PPC_GOT_TPREL16_HA: 117 Type = ELF::R_PPC64_GOT_TPREL16_HA; 118 break; 119 case MCSymbolRefExpr::VK_PPC_GOT_TLSGD16_HA: 120 Type = ELF::R_PPC64_GOT_TLSGD16_HA; 121 break; 122 case MCSymbolRefExpr::VK_PPC_GOT_TLSLD16_HA: 123 Type = ELF::R_PPC64_GOT_TLSLD16_HA; 124 break; 125 } 126 break; 127 case PPC::fixup_ppc_lo16: 128 switch (Modifier) { 129 default: llvm_unreachable("Unsupported Modifier"); 130 case MCSymbolRefExpr::VK_PPC_TPREL16_LO: 131 Type = ELF::R_PPC_TPREL16_LO; 132 break; 133 case MCSymbolRefExpr::VK_PPC_DTPREL16_LO: 134 Type = ELF::R_PPC64_DTPREL16_LO; 135 break; 136 case MCSymbolRefExpr::VK_None: 137 Type = ELF::R_PPC_ADDR16; 138 break; 139 case MCSymbolRefExpr::VK_PPC_GAS_LO16: 140 case MCSymbolRefExpr::VK_PPC_DARWIN_LO16: 141 Type = ELF::R_PPC_ADDR16_LO; 142 break; 143 case MCSymbolRefExpr::VK_PPC_TOC_ENTRY: 144 Type = ELF::R_PPC64_TOC16; 145 break; 146 case MCSymbolRefExpr::VK_PPC_TOC16_LO: 147 Type = ELF::R_PPC64_TOC16_LO; 148 break; 149 case MCSymbolRefExpr::VK_PPC_GOT_TLSGD16_LO: 150 Type = ELF::R_PPC64_GOT_TLSGD16_LO; 151 break; 152 case MCSymbolRefExpr::VK_PPC_GOT_TLSLD16_LO: 153 Type = ELF::R_PPC64_GOT_TLSLD16_LO; 154 break; 155 } 156 break; 157 case PPC::fixup_ppc_lo16_ds: 158 switch (Modifier) { 159 default: llvm_unreachable("Unsupported Modifier"); 160 case MCSymbolRefExpr::VK_None: 161 Type = ELF::R_PPC64_ADDR16_DS; 162 break; 163 case MCSymbolRefExpr::VK_PPC_GAS_LO16: 164 case MCSymbolRefExpr::VK_PPC_DARWIN_LO16: 165 Type = ELF::R_PPC64_ADDR16_LO_DS; 166 break; 167 case MCSymbolRefExpr::VK_PPC_TOC_ENTRY: 168 Type = ELF::R_PPC64_TOC16_DS; 169 break; 170 case MCSymbolRefExpr::VK_PPC_TOC16_LO: 171 Type = ELF::R_PPC64_TOC16_LO_DS; 172 break; 173 case MCSymbolRefExpr::VK_PPC_GOT_TPREL16_LO: 174 Type = ELF::R_PPC64_GOT_TPREL16_LO_DS; 175 break; 176 } 177 break; 178 case PPC::fixup_ppc_tlsreg: 179 Type = ELF::R_PPC64_TLS; 180 break; 181 case PPC::fixup_ppc_nofixup: 182 switch (Modifier) { 183 default: llvm_unreachable("Unsupported Modifier"); 184 case MCSymbolRefExpr::VK_PPC_TLSGD: 185 Type = ELF::R_PPC64_TLSGD; 186 break; 187 case MCSymbolRefExpr::VK_PPC_TLSLD: 188 Type = ELF::R_PPC64_TLSLD; 189 break; 190 } 191 break; 192 case FK_Data_8: 193 switch (Modifier) { 194 default: llvm_unreachable("Unsupported Modifier"); 195 case MCSymbolRefExpr::VK_PPC_TOC: 196 Type = ELF::R_PPC64_TOC; 197 break; 198 case MCSymbolRefExpr::VK_None: 199 Type = ELF::R_PPC64_ADDR64; 200 break; 201 } 202 break; 203 case FK_Data_4: 204 Type = ELF::R_PPC_ADDR32; 205 break; 206 case FK_Data_2: 207 Type = ELF::R_PPC_ADDR16; 208 break; 209 } 210 } 211 return Type; 212 } 213 214 unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target, 215 const MCFixup &Fixup, 216 bool IsPCRel, 217 bool IsRelocWithSymbol, 218 int64_t Addend) const { 219 return getRelocTypeInner(Target, Fixup, IsPCRel); 220 } 221 222 const MCSymbol *PPCELFObjectWriter::undefinedExplicitRelSym(const MCValue &Target, 223 const MCFixup &Fixup, 224 bool IsPCRel) const { 225 assert(Target.getSymA() && "SymA cannot be 0"); 226 const MCSymbol &Symbol = Target.getSymA()->getSymbol().AliasedSymbol(); 227 228 unsigned RelocType = getRelocTypeInner(Target, Fixup, IsPCRel); 229 230 // The .odp creation emits a relocation against the symbol ".TOC." which 231 // create a R_PPC64_TOC relocation. However the relocation symbol name 232 // in final object creation should be NULL, since the symbol does not 233 // really exist, it is just the reference to TOC base for the current 234 // object file. 235 bool EmitThisSym = RelocType != ELF::R_PPC64_TOC; 236 237 if (EmitThisSym && !Symbol.isTemporary()) 238 return &Symbol; 239 return NULL; 240 } 241 242 // The standard sorter only sorts on the r_offset field, but PowerPC can 243 // have multiple relocations at the same offset. Sort secondarily on the 244 // relocation type to avoid nondeterminism. 245 void PPCELFObjectWriter::sortRelocs(const MCAssembler &Asm, 246 std::vector<ELFRelocationEntry> &Relocs) { 247 248 // Copy to a temporary vector of relocation entries having a different 249 // sort function. 250 std::vector<PPCELFRelocationEntry> TmpRelocs; 251 252 for (std::vector<ELFRelocationEntry>::iterator R = Relocs.begin(); 253 R != Relocs.end(); ++R) { 254 TmpRelocs.push_back(PPCELFRelocationEntry(*R)); 255 } 256 257 // Sort in place by ascending r_offset and descending r_type. 258 array_pod_sort(TmpRelocs.begin(), TmpRelocs.end()); 259 260 // Copy back to the original vector. 261 unsigned I = 0; 262 for (std::vector<PPCELFRelocationEntry>::iterator R = TmpRelocs.begin(); 263 R != TmpRelocs.end(); ++R, ++I) { 264 Relocs[I] = ELFRelocationEntry(R->r_offset, R->Index, R->Type, 265 R->Symbol, R->r_addend, *R->Fixup); 266 } 267 } 268 269 270 MCObjectWriter *llvm::createPPCELFObjectWriter(raw_ostream &OS, 271 bool Is64Bit, 272 uint8_t OSABI) { 273 MCELFObjectTargetWriter *MOTW = new PPCELFObjectWriter(Is64Bit, OSABI); 274 return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false); 275 } 276