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