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