1 //===-- X86ELFObjectWriter.cpp - X86 ELF Writer ---------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "MCTargetDesc/X86FixupKinds.h" 10 #include "MCTargetDesc/X86MCTargetDesc.h" 11 #include "llvm/BinaryFormat/ELF.h" 12 #include "llvm/MC/MCAsmInfo.h" 13 #include "llvm/MC/MCContext.h" 14 #include "llvm/MC/MCELFObjectWriter.h" 15 #include "llvm/MC/MCExpr.h" 16 #include "llvm/MC/MCFixup.h" 17 #include "llvm/MC/MCObjectWriter.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_NONE, RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 }; 48 49 static X86_64RelType getType64(MCFixupKind Kind, 50 MCSymbolRefExpr::VariantKind &Modifier, 51 bool &IsPCRel) { 52 switch (unsigned(Kind)) { 53 default: 54 llvm_unreachable("Unimplemented"); 55 case FK_NONE: 56 return RT64_NONE; 57 case X86::reloc_global_offset_table8: 58 Modifier = MCSymbolRefExpr::VK_GOT; 59 IsPCRel = true; 60 return RT64_64; 61 case FK_Data_8: 62 return RT64_64; 63 case X86::reloc_signed_4byte: 64 case X86::reloc_signed_4byte_relax: 65 if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel) 66 return RT64_32S; 67 return RT64_32; 68 case X86::reloc_global_offset_table: 69 Modifier = MCSymbolRefExpr::VK_GOT; 70 IsPCRel = true; 71 return RT64_32; 72 case FK_Data_4: 73 case FK_PCRel_4: 74 case X86::reloc_riprel_4byte: 75 case X86::reloc_riprel_4byte_relax: 76 case X86::reloc_riprel_4byte_relax_rex: 77 case X86::reloc_riprel_4byte_movq_load: 78 return RT64_32; 79 case X86::reloc_branch_4byte_pcrel: 80 Modifier = MCSymbolRefExpr::VK_PLT; 81 return RT64_32; 82 case FK_PCRel_2: 83 case FK_Data_2: 84 return RT64_16; 85 case FK_PCRel_1: 86 case FK_Data_1: 87 return RT64_8; 88 } 89 } 90 91 static void checkIs32(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) { 92 if (Type != RT64_32) 93 Ctx.reportError(Loc, 94 "32 bit reloc applied to a field with a different size"); 95 } 96 97 static void checkIs64(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) { 98 if (Type != RT64_64) 99 Ctx.reportError(Loc, 100 "64 bit reloc applied to a field with a different size"); 101 } 102 103 static unsigned getRelocType64(MCContext &Ctx, SMLoc Loc, 104 MCSymbolRefExpr::VariantKind Modifier, 105 X86_64RelType Type, bool IsPCRel, 106 MCFixupKind Kind) { 107 switch (Modifier) { 108 default: 109 llvm_unreachable("Unimplemented"); 110 case MCSymbolRefExpr::VK_None: 111 case MCSymbolRefExpr::VK_X86_ABS8: 112 switch (Type) { 113 case RT64_NONE: 114 if (Modifier == MCSymbolRefExpr::VK_None) 115 return ELF::R_X86_64_NONE; 116 llvm_unreachable("Unimplemented"); 117 case RT64_64: 118 return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64; 119 case RT64_32: 120 return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32; 121 case RT64_32S: 122 return ELF::R_X86_64_32S; 123 case RT64_16: 124 return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16; 125 case RT64_8: 126 return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8; 127 } 128 llvm_unreachable("unexpected relocation type!"); 129 case MCSymbolRefExpr::VK_GOT: 130 switch (Type) { 131 case RT64_64: 132 return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64; 133 case RT64_32: 134 return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32; 135 case RT64_32S: 136 case RT64_16: 137 case RT64_8: 138 case RT64_NONE: 139 llvm_unreachable("Unimplemented"); 140 } 141 llvm_unreachable("unexpected relocation type!"); 142 case MCSymbolRefExpr::VK_GOTOFF: 143 assert(Type == RT64_64); 144 assert(!IsPCRel); 145 return ELF::R_X86_64_GOTOFF64; 146 case MCSymbolRefExpr::VK_TPOFF: 147 assert(!IsPCRel); 148 switch (Type) { 149 case RT64_64: 150 return ELF::R_X86_64_TPOFF64; 151 case RT64_32: 152 return ELF::R_X86_64_TPOFF32; 153 case RT64_32S: 154 case RT64_16: 155 case RT64_8: 156 case RT64_NONE: 157 llvm_unreachable("Unimplemented"); 158 } 159 llvm_unreachable("unexpected relocation type!"); 160 case MCSymbolRefExpr::VK_DTPOFF: 161 assert(!IsPCRel); 162 switch (Type) { 163 case RT64_64: 164 return ELF::R_X86_64_DTPOFF64; 165 case RT64_32: 166 return ELF::R_X86_64_DTPOFF32; 167 case RT64_32S: 168 case RT64_16: 169 case RT64_8: 170 case RT64_NONE: 171 llvm_unreachable("Unimplemented"); 172 } 173 llvm_unreachable("unexpected relocation type!"); 174 case MCSymbolRefExpr::VK_SIZE: 175 assert(!IsPCRel); 176 switch (Type) { 177 case RT64_64: 178 return ELF::R_X86_64_SIZE64; 179 case RT64_32: 180 return ELF::R_X86_64_SIZE32; 181 case RT64_32S: 182 case RT64_16: 183 case RT64_8: 184 case RT64_NONE: 185 llvm_unreachable("Unimplemented"); 186 } 187 llvm_unreachable("unexpected relocation type!"); 188 case MCSymbolRefExpr::VK_TLSCALL: 189 return ELF::R_X86_64_TLSDESC_CALL; 190 case MCSymbolRefExpr::VK_TLSDESC: 191 return ELF::R_X86_64_GOTPC32_TLSDESC; 192 case MCSymbolRefExpr::VK_TLSGD: 193 checkIs32(Ctx, Loc, Type); 194 return ELF::R_X86_64_TLSGD; 195 case MCSymbolRefExpr::VK_GOTTPOFF: 196 checkIs32(Ctx, Loc, Type); 197 return ELF::R_X86_64_GOTTPOFF; 198 case MCSymbolRefExpr::VK_TLSLD: 199 checkIs32(Ctx, Loc, Type); 200 return ELF::R_X86_64_TLSLD; 201 case MCSymbolRefExpr::VK_PLT: 202 checkIs32(Ctx, Loc, Type); 203 return ELF::R_X86_64_PLT32; 204 case MCSymbolRefExpr::VK_GOTPCREL: 205 checkIs32(Ctx, Loc, Type); 206 // Older versions of ld.bfd/ld.gold/lld 207 // do not support GOTPCRELX/REX_GOTPCRELX, 208 // and we want to keep back-compatibility. 209 if (!Ctx.getAsmInfo()->canRelaxRelocations()) 210 return ELF::R_X86_64_GOTPCREL; 211 switch (unsigned(Kind)) { 212 default: 213 return ELF::R_X86_64_GOTPCREL; 214 case X86::reloc_riprel_4byte_relax: 215 return ELF::R_X86_64_GOTPCRELX; 216 case X86::reloc_riprel_4byte_relax_rex: 217 case X86::reloc_riprel_4byte_movq_load: 218 return ELF::R_X86_64_REX_GOTPCRELX; 219 } 220 llvm_unreachable("unexpected relocation type!"); 221 case MCSymbolRefExpr::VK_GOTPCREL_NORELAX: 222 checkIs32(Ctx, Loc, Type); 223 return ELF::R_X86_64_GOTPCREL; 224 case MCSymbolRefExpr::VK_X86_PLTOFF: 225 checkIs64(Ctx, Loc, Type); 226 return ELF::R_X86_64_PLTOFF64; 227 } 228 } 229 230 enum X86_32RelType { RT32_NONE, RT32_32, RT32_16, RT32_8 }; 231 232 static X86_32RelType getType32(X86_64RelType T) { 233 switch (T) { 234 case RT64_NONE: 235 return RT32_NONE; 236 case RT64_64: 237 llvm_unreachable("Unimplemented"); 238 case RT64_32: 239 case RT64_32S: 240 return RT32_32; 241 case RT64_16: 242 return RT32_16; 243 case RT64_8: 244 return RT32_8; 245 } 246 llvm_unreachable("unexpected relocation type!"); 247 } 248 249 static unsigned getRelocType32(MCContext &Ctx, 250 MCSymbolRefExpr::VariantKind Modifier, 251 X86_32RelType Type, bool IsPCRel, 252 MCFixupKind Kind) { 253 switch (Modifier) { 254 default: 255 llvm_unreachable("Unimplemented"); 256 case MCSymbolRefExpr::VK_None: 257 case MCSymbolRefExpr::VK_X86_ABS8: 258 switch (Type) { 259 case RT32_NONE: 260 if (Modifier == MCSymbolRefExpr::VK_None) 261 return ELF::R_386_NONE; 262 llvm_unreachable("Unimplemented"); 263 case RT32_32: 264 return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32; 265 case RT32_16: 266 return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16; 267 case RT32_8: 268 return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8; 269 } 270 llvm_unreachable("unexpected relocation type!"); 271 case MCSymbolRefExpr::VK_GOT: 272 assert(Type == RT32_32); 273 if (IsPCRel) 274 return ELF::R_386_GOTPC; 275 // Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we 276 // want to maintain compatibility. 277 if (!Ctx.getAsmInfo()->canRelaxRelocations()) 278 return ELF::R_386_GOT32; 279 280 return Kind == MCFixupKind(X86::reloc_signed_4byte_relax) 281 ? ELF::R_386_GOT32X 282 : ELF::R_386_GOT32; 283 case MCSymbolRefExpr::VK_GOTOFF: 284 assert(Type == RT32_32); 285 assert(!IsPCRel); 286 return ELF::R_386_GOTOFF; 287 case MCSymbolRefExpr::VK_TLSCALL: 288 return ELF::R_386_TLS_DESC_CALL; 289 case MCSymbolRefExpr::VK_TLSDESC: 290 return ELF::R_386_TLS_GOTDESC; 291 case MCSymbolRefExpr::VK_TPOFF: 292 assert(Type == RT32_32); 293 assert(!IsPCRel); 294 return ELF::R_386_TLS_LE_32; 295 case MCSymbolRefExpr::VK_DTPOFF: 296 assert(Type == RT32_32); 297 assert(!IsPCRel); 298 return ELF::R_386_TLS_LDO_32; 299 case MCSymbolRefExpr::VK_TLSGD: 300 assert(Type == RT32_32); 301 assert(!IsPCRel); 302 return ELF::R_386_TLS_GD; 303 case MCSymbolRefExpr::VK_GOTTPOFF: 304 assert(Type == RT32_32); 305 assert(!IsPCRel); 306 return ELF::R_386_TLS_IE_32; 307 case MCSymbolRefExpr::VK_PLT: 308 assert(Type == RT32_32); 309 return ELF::R_386_PLT32; 310 case MCSymbolRefExpr::VK_INDNTPOFF: 311 assert(Type == RT32_32); 312 assert(!IsPCRel); 313 return ELF::R_386_TLS_IE; 314 case MCSymbolRefExpr::VK_NTPOFF: 315 assert(Type == RT32_32); 316 assert(!IsPCRel); 317 return ELF::R_386_TLS_LE; 318 case MCSymbolRefExpr::VK_GOTNTPOFF: 319 assert(Type == RT32_32); 320 assert(!IsPCRel); 321 return ELF::R_386_TLS_GOTIE; 322 case MCSymbolRefExpr::VK_TLSLDM: 323 assert(Type == RT32_32); 324 assert(!IsPCRel); 325 return ELF::R_386_TLS_LDM; 326 } 327 } 328 329 unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, 330 const MCFixup &Fixup, 331 bool IsPCRel) const { 332 MCFixupKind Kind = Fixup.getKind(); 333 if (Kind >= FirstLiteralRelocationKind) 334 return Kind - FirstLiteralRelocationKind; 335 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); 336 X86_64RelType Type = getType64(Kind, Modifier, IsPCRel); 337 if (getEMachine() == ELF::EM_X86_64) 338 return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel, Kind); 339 340 assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) && 341 "Unsupported ELF machine type."); 342 return getRelocType32(Ctx, Modifier, getType32(Type), IsPCRel, Kind); 343 } 344 345 std::unique_ptr<MCObjectTargetWriter> 346 llvm::createX86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine) { 347 return std::make_unique<X86ELFObjectWriter>(IsELF64, OSABI, EMachine); 348 } 349