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