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