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/MC/MCELFObjectWriter.h" 13 #include "llvm/MC/MCExpr.h" 14 #include "llvm/MC/MCValue.h" 15 #include "llvm/Support/ErrorHandling.h" 16 17 using namespace llvm; 18 19 namespace { 20 class PPCELFObjectWriter : public MCELFObjectTargetWriter { 21 public: 22 PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI); 23 24 virtual ~PPCELFObjectWriter(); 25 protected: 26 virtual unsigned getRelocTypeInner(const MCValue &Target, 27 const MCFixup &Fixup, 28 bool IsPCRel) const; 29 virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, 30 bool IsPCRel, bool IsRelocWithSymbol, 31 int64_t Addend) const; 32 virtual const MCSymbol *undefinedExplicitRelSym(const MCValue &Target, 33 const MCFixup &Fixup, 34 bool IsPCRel) const; 35 virtual void adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset); 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 FK_PCRel_4: 64 Type = ELF::R_PPC_REL32; 65 break; 66 } 67 } else { 68 switch ((unsigned)Fixup.getKind()) { 69 default: llvm_unreachable("invalid fixup kind!"); 70 case PPC::fixup_ppc_br24: 71 Type = ELF::R_PPC_ADDR24; 72 break; 73 case PPC::fixup_ppc_brcond14: 74 Type = ELF::R_PPC_ADDR14; // XXX: or BRNTAKEN?_ 75 break; 76 case PPC::fixup_ppc_ha16: 77 switch (Modifier) { 78 default: llvm_unreachable("Unsupported Modifier"); 79 case MCSymbolRefExpr::VK_PPC_TPREL16_HA: 80 Type = ELF::R_PPC_TPREL16_HA; 81 break; 82 case MCSymbolRefExpr::VK_None: 83 Type = ELF::R_PPC_ADDR16_HA; 84 break; 85 case MCSymbolRefExpr::VK_PPC_TOC16_HA: 86 Type = ELF::R_PPC64_TOC16_HA; 87 break; 88 } 89 break; 90 case PPC::fixup_ppc_lo16: 91 switch (Modifier) { 92 default: llvm_unreachable("Unsupported Modifier"); 93 case MCSymbolRefExpr::VK_PPC_TPREL16_LO: 94 Type = ELF::R_PPC_TPREL16_LO; 95 break; 96 case MCSymbolRefExpr::VK_None: 97 Type = ELF::R_PPC_ADDR16_LO; 98 break; 99 case MCSymbolRefExpr::VK_PPC_TOC16_LO: 100 Type = ELF::R_PPC64_TOC16_LO; 101 break; 102 } 103 break; 104 case PPC::fixup_ppc_lo14: 105 Type = ELF::R_PPC_ADDR14; 106 break; 107 case PPC::fixup_ppc_toc: 108 Type = ELF::R_PPC64_TOC; 109 break; 110 case PPC::fixup_ppc_toc16: 111 Type = ELF::R_PPC64_TOC16; 112 break; 113 case PPC::fixup_ppc_toc16_ds: 114 switch (Modifier) { 115 default: llvm_unreachable("Unsupported Modifier"); 116 case MCSymbolRefExpr::VK_PPC_TOC_ENTRY: 117 Type = ELF::R_PPC64_TOC16_DS; 118 break; 119 case MCSymbolRefExpr::VK_PPC_TOC16_LO: 120 Type = ELF::R_PPC64_TOC16_LO_DS; 121 break; 122 } 123 break; 124 case FK_Data_8: 125 switch (Modifier) { 126 default: llvm_unreachable("Unsupported Modifier"); 127 case MCSymbolRefExpr::VK_PPC_TOC: 128 Type = ELF::R_PPC64_TOC; 129 break; 130 case MCSymbolRefExpr::VK_None: 131 Type = ELF::R_PPC64_ADDR64; 132 break; 133 } 134 break; 135 case FK_Data_4: 136 Type = ELF::R_PPC_ADDR32; 137 break; 138 case FK_Data_2: 139 Type = ELF::R_PPC_ADDR16; 140 break; 141 } 142 } 143 return Type; 144 } 145 146 unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target, 147 const MCFixup &Fixup, 148 bool IsPCRel, 149 bool IsRelocWithSymbol, 150 int64_t Addend) const { 151 return getRelocTypeInner(Target, Fixup, IsPCRel); 152 } 153 154 const MCSymbol *PPCELFObjectWriter::undefinedExplicitRelSym(const MCValue &Target, 155 const MCFixup &Fixup, 156 bool IsPCRel) const { 157 assert(Target.getSymA() && "SymA cannot be 0"); 158 const MCSymbol &Symbol = Target.getSymA()->getSymbol().AliasedSymbol(); 159 160 unsigned RelocType = getRelocTypeInner(Target, Fixup, IsPCRel); 161 162 // The .odp creation emits a relocation against the symbol ".TOC." which 163 // create a R_PPC64_TOC relocation. However the relocation symbol name 164 // in final object creation should be NULL, since the symbol does not 165 // really exist, it is just the reference to TOC base for the current 166 // object file. 167 bool EmitThisSym = RelocType != ELF::R_PPC64_TOC; 168 169 if (EmitThisSym && !Symbol.isTemporary()) 170 return &Symbol; 171 return NULL; 172 } 173 174 void PPCELFObjectWriter:: 175 adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset) { 176 switch ((unsigned)Fixup.getKind()) { 177 case PPC::fixup_ppc_ha16: 178 case PPC::fixup_ppc_lo16: 179 case PPC::fixup_ppc_toc16: 180 case PPC::fixup_ppc_toc16_ds: 181 RelocOffset += 2; 182 break; 183 default: 184 break; 185 } 186 } 187 188 MCObjectWriter *llvm::createPPCELFObjectWriter(raw_ostream &OS, 189 bool Is64Bit, 190 uint8_t OSABI) { 191 MCELFObjectTargetWriter *MOTW = new PPCELFObjectWriter(Is64Bit, OSABI); 192 return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false); 193 } 194