1 //===-- X86ELFObjectWriter.cpp - X86 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/X86FixupKinds.h" 11 #include "MCTargetDesc/X86MCTargetDesc.h" 12 #include "llvm/MC/MCELFObjectWriter.h" 13 #include "llvm/MC/MCExpr.h" 14 #include "llvm/MC/MCValue.h" 15 #include "llvm/Support/ELF.h" 16 #include "llvm/Support/ErrorHandling.h" 17 18 using namespace llvm; 19 20 namespace { 21 class X86ELFObjectWriter : public MCELFObjectTargetWriter { 22 public: 23 X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine); 24 25 virtual ~X86ELFObjectWriter(); 26 protected: 27 unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, 28 bool IsPCRel) const override; 29 }; 30 } 31 32 X86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, 33 uint16_t EMachine) 34 : MCELFObjectTargetWriter(IsELF64, OSABI, EMachine, 35 // Only i386 uses Rel instead of RelA. 36 /*HasRelocationAddend*/ EMachine != ELF::EM_386) {} 37 38 X86ELFObjectWriter::~X86ELFObjectWriter() 39 {} 40 41 enum X86_64RelType { RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 }; 42 43 static X86_64RelType getType64(unsigned Kind, 44 MCSymbolRefExpr::VariantKind &Modifier, 45 bool &IsPCRel) { 46 switch (Kind) { 47 default: 48 llvm_unreachable("Unimplemented"); 49 case X86::reloc_global_offset_table8: 50 Modifier = MCSymbolRefExpr::VK_GOT; 51 IsPCRel = true; 52 return RT64_64; 53 case FK_Data_8: 54 return RT64_64; 55 case X86::reloc_signed_4byte: 56 if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel) 57 return RT64_32S; 58 return RT64_32; 59 case X86::reloc_global_offset_table: 60 Modifier = MCSymbolRefExpr::VK_GOT; 61 IsPCRel = true; 62 return RT64_32; 63 case FK_Data_4: 64 case FK_PCRel_4: 65 case X86::reloc_riprel_4byte: 66 case X86::reloc_riprel_4byte_movq_load: 67 return RT64_32; 68 case FK_Data_2: 69 return RT64_16; 70 case FK_PCRel_1: 71 case FK_Data_1: 72 return RT64_8; 73 } 74 } 75 76 static unsigned getRelocType64(MCSymbolRefExpr::VariantKind Modifier, 77 X86_64RelType Type, bool IsPCRel) { 78 switch (Modifier) { 79 default: 80 llvm_unreachable("Unimplemented"); 81 case MCSymbolRefExpr::VK_None: 82 switch (Type) { 83 case RT64_64: 84 return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64; 85 case RT64_32: 86 return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32; 87 case RT64_32S: 88 return ELF::R_X86_64_32S; 89 case RT64_16: 90 return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16; 91 case RT64_8: 92 return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8; 93 } 94 case MCSymbolRefExpr::VK_GOT: 95 switch (Type) { 96 case RT64_64: 97 return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64; 98 case RT64_32: 99 return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32; 100 case RT64_32S: 101 case RT64_16: 102 case RT64_8: 103 llvm_unreachable("Unimplemented"); 104 } 105 case MCSymbolRefExpr::VK_GOTOFF: 106 assert(Type == RT64_64); 107 assert(!IsPCRel); 108 return ELF::R_X86_64_GOTOFF64; 109 case MCSymbolRefExpr::VK_TPOFF: 110 assert(!IsPCRel); 111 switch (Type) { 112 case RT64_64: 113 return ELF::R_X86_64_TPOFF64; 114 case RT64_32: 115 return ELF::R_X86_64_TPOFF32; 116 case RT64_32S: 117 case RT64_16: 118 case RT64_8: 119 llvm_unreachable("Unimplemented"); 120 } 121 case MCSymbolRefExpr::VK_DTPOFF: 122 assert(!IsPCRel); 123 switch (Type) { 124 case RT64_64: 125 return ELF::R_X86_64_DTPOFF64; 126 case RT64_32: 127 return ELF::R_X86_64_DTPOFF32; 128 case RT64_32S: 129 case RT64_16: 130 case RT64_8: 131 llvm_unreachable("Unimplemented"); 132 } 133 case MCSymbolRefExpr::VK_SIZE: 134 assert(!IsPCRel); 135 switch (Type) { 136 case RT64_64: 137 return ELF::R_X86_64_SIZE64; 138 case RT64_32: 139 return ELF::R_X86_64_SIZE32; 140 case RT64_32S: 141 case RT64_16: 142 case RT64_8: 143 llvm_unreachable("Unimplemented"); 144 } 145 case MCSymbolRefExpr::VK_TLSGD: 146 assert(Type == RT64_32); 147 return ELF::R_X86_64_TLSGD; 148 case MCSymbolRefExpr::VK_GOTTPOFF: 149 assert(Type == RT64_32); 150 return ELF::R_X86_64_GOTTPOFF; 151 case MCSymbolRefExpr::VK_TLSLD: 152 assert(Type == RT64_32); 153 return ELF::R_X86_64_TLSLD; 154 case MCSymbolRefExpr::VK_PLT: 155 assert(Type == RT64_32); 156 return ELF::R_X86_64_PLT32; 157 case MCSymbolRefExpr::VK_GOTPCREL: 158 assert(Type == RT64_32); 159 return ELF::R_X86_64_GOTPCREL; 160 } 161 } 162 163 enum X86_32RelType { RT32_32, RT32_16, RT32_8 }; 164 165 static X86_32RelType getType32(X86_64RelType T) { 166 switch (T) { 167 case RT64_64: 168 llvm_unreachable("Unimplemented"); 169 case RT64_32: 170 case RT64_32S: 171 return RT32_32; 172 case RT64_16: 173 return RT32_16; 174 case RT64_8: 175 return RT32_8; 176 } 177 llvm_unreachable("unexpected relocation type!"); 178 } 179 180 static unsigned getRelocType32(MCSymbolRefExpr::VariantKind Modifier, 181 X86_32RelType Type, bool IsPCRel) { 182 switch (Modifier) { 183 default: 184 llvm_unreachable("Unimplemented"); 185 case MCSymbolRefExpr::VK_None: 186 switch (Type) { 187 case RT32_32: 188 return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32; 189 case RT32_16: 190 return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16; 191 case RT32_8: 192 return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8; 193 } 194 case MCSymbolRefExpr::VK_GOT: 195 assert(Type == RT32_32); 196 return IsPCRel ? ELF::R_386_GOTPC : ELF::R_386_GOT32; 197 case MCSymbolRefExpr::VK_GOTOFF: 198 assert(Type == RT32_32); 199 assert(!IsPCRel); 200 return ELF::R_386_GOTOFF; 201 case MCSymbolRefExpr::VK_TPOFF: 202 assert(Type == RT32_32); 203 assert(!IsPCRel); 204 return ELF::R_386_TLS_LE_32; 205 case MCSymbolRefExpr::VK_DTPOFF: 206 assert(Type == RT32_32); 207 assert(!IsPCRel); 208 return ELF::R_386_TLS_LDO_32; 209 case MCSymbolRefExpr::VK_TLSGD: 210 assert(Type == RT32_32); 211 assert(!IsPCRel); 212 return ELF::R_386_TLS_GD; 213 case MCSymbolRefExpr::VK_GOTTPOFF: 214 assert(Type == RT32_32); 215 assert(!IsPCRel); 216 return ELF::R_386_TLS_IE_32; 217 case MCSymbolRefExpr::VK_PLT: 218 assert(Type == RT32_32); 219 return ELF::R_386_PLT32; 220 case MCSymbolRefExpr::VK_INDNTPOFF: 221 assert(Type == RT32_32); 222 assert(!IsPCRel); 223 return ELF::R_386_TLS_IE; 224 case MCSymbolRefExpr::VK_NTPOFF: 225 assert(Type == RT32_32); 226 assert(!IsPCRel); 227 return ELF::R_386_TLS_LE; 228 case MCSymbolRefExpr::VK_GOTNTPOFF: 229 assert(Type == RT32_32); 230 assert(!IsPCRel); 231 return ELF::R_386_TLS_GOTIE; 232 case MCSymbolRefExpr::VK_TLSLDM: 233 assert(Type == RT32_32); 234 assert(!IsPCRel); 235 return ELF::R_386_TLS_LDM; 236 } 237 } 238 239 unsigned X86ELFObjectWriter::GetRelocType(const MCValue &Target, 240 const MCFixup &Fixup, 241 bool IsPCRel) const { 242 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); 243 X86_64RelType Type = getType64(Fixup.getKind(), Modifier, IsPCRel); 244 if (getEMachine() == ELF::EM_X86_64) 245 return getRelocType64(Modifier, Type, IsPCRel); 246 247 assert(getEMachine() == ELF::EM_386 && "Unsupported ELF machine type."); 248 return getRelocType32(Modifier, getType32(Type), IsPCRel); 249 } 250 251 MCObjectWriter *llvm::createX86ELFObjectWriter(raw_ostream &OS, 252 bool IsELF64, 253 uint8_t OSABI, 254 uint16_t EMachine) { 255 MCELFObjectTargetWriter *MOTW = 256 new X86ELFObjectWriter(IsELF64, OSABI, EMachine); 257 return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/true); 258 } 259