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_relax_rex2: 78 case X86::reloc_riprel_4byte_movq_load: 79 case X86::reloc_riprel_4byte_movq_load_rex2: 80 case X86::reloc_riprel_4byte_relax_evex: 81 return RT64_32; 82 case X86::reloc_branch_4byte_pcrel: 83 Modifier = MCSymbolRefExpr::VK_PLT; 84 return RT64_32; 85 case FK_PCRel_2: 86 case FK_Data_2: 87 return RT64_16; 88 case FK_PCRel_1: 89 case FK_Data_1: 90 return RT64_8; 91 } 92 } 93 94 static void checkIs32(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) { 95 if (Type != RT64_32) 96 Ctx.reportError(Loc, 97 "32 bit reloc applied to a field with a different size"); 98 } 99 100 static void checkIs64(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) { 101 if (Type != RT64_64) 102 Ctx.reportError(Loc, 103 "64 bit reloc applied to a field with a different size"); 104 } 105 106 static unsigned getRelocType64(MCContext &Ctx, SMLoc Loc, 107 MCSymbolRefExpr::VariantKind Modifier, 108 X86_64RelType Type, bool IsPCRel, 109 MCFixupKind Kind) { 110 switch (Modifier) { 111 default: 112 llvm_unreachable("Unimplemented"); 113 case MCSymbolRefExpr::VK_None: 114 case MCSymbolRefExpr::VK_X86_ABS8: 115 switch (Type) { 116 case RT64_NONE: 117 if (Modifier == MCSymbolRefExpr::VK_None) 118 return ELF::R_X86_64_NONE; 119 llvm_unreachable("Unimplemented"); 120 case RT64_64: 121 return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64; 122 case RT64_32: 123 return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32; 124 case RT64_32S: 125 return ELF::R_X86_64_32S; 126 case RT64_16: 127 return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16; 128 case RT64_8: 129 return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8; 130 } 131 llvm_unreachable("unexpected relocation type!"); 132 case MCSymbolRefExpr::VK_GOT: 133 switch (Type) { 134 case RT64_64: 135 return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64; 136 case RT64_32: 137 return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32; 138 case RT64_32S: 139 case RT64_16: 140 case RT64_8: 141 case RT64_NONE: 142 llvm_unreachable("Unimplemented"); 143 } 144 llvm_unreachable("unexpected relocation type!"); 145 case MCSymbolRefExpr::VK_GOTOFF: 146 assert(!IsPCRel); 147 if (Type != RT64_64) 148 Ctx.reportError(Loc, "unsupported relocation type"); 149 return ELF::R_X86_64_GOTOFF64; 150 case MCSymbolRefExpr::VK_TPOFF: 151 assert(!IsPCRel); 152 switch (Type) { 153 case RT64_64: 154 return ELF::R_X86_64_TPOFF64; 155 case RT64_32: 156 return ELF::R_X86_64_TPOFF32; 157 case RT64_32S: 158 case RT64_16: 159 case RT64_8: 160 case RT64_NONE: 161 llvm_unreachable("Unimplemented"); 162 } 163 llvm_unreachable("unexpected relocation type!"); 164 case MCSymbolRefExpr::VK_DTPOFF: 165 assert(!IsPCRel); 166 switch (Type) { 167 case RT64_64: 168 return ELF::R_X86_64_DTPOFF64; 169 case RT64_32: 170 return ELF::R_X86_64_DTPOFF32; 171 case RT64_32S: 172 case RT64_16: 173 case RT64_8: 174 case RT64_NONE: 175 llvm_unreachable("Unimplemented"); 176 } 177 llvm_unreachable("unexpected relocation type!"); 178 case MCSymbolRefExpr::VK_SIZE: 179 assert(!IsPCRel); 180 switch (Type) { 181 case RT64_64: 182 return ELF::R_X86_64_SIZE64; 183 case RT64_32: 184 return ELF::R_X86_64_SIZE32; 185 case RT64_32S: 186 case RT64_16: 187 case RT64_8: 188 case RT64_NONE: 189 llvm_unreachable("Unimplemented"); 190 } 191 llvm_unreachable("unexpected relocation type!"); 192 case MCSymbolRefExpr::VK_TLSCALL: 193 return ELF::R_X86_64_TLSDESC_CALL; 194 case MCSymbolRefExpr::VK_TLSDESC: 195 return ((unsigned)Kind == X86::reloc_riprel_4byte_relax_rex2) 196 ? ELF::R_X86_64_CODE_4_GOTPC32_TLSDESC 197 : ELF::R_X86_64_GOTPC32_TLSDESC; 198 case MCSymbolRefExpr::VK_TLSGD: 199 checkIs32(Ctx, Loc, Type); 200 return ELF::R_X86_64_TLSGD; 201 case MCSymbolRefExpr::VK_GOTTPOFF: 202 checkIs32(Ctx, Loc, Type); 203 if ((unsigned)Kind == X86::reloc_riprel_4byte_movq_load_rex2 || 204 (unsigned)Kind == X86::reloc_riprel_4byte_relax_rex2) 205 return ELF::R_X86_64_CODE_4_GOTTPOFF; 206 else if ((unsigned)Kind == X86::reloc_riprel_4byte_relax_evex) 207 return ELF::R_X86_64_CODE_6_GOTTPOFF; 208 return ELF::R_X86_64_GOTTPOFF; 209 case MCSymbolRefExpr::VK_TLSLD: 210 checkIs32(Ctx, Loc, Type); 211 return ELF::R_X86_64_TLSLD; 212 case MCSymbolRefExpr::VK_PLT: 213 checkIs32(Ctx, Loc, Type); 214 return ELF::R_X86_64_PLT32; 215 case MCSymbolRefExpr::VK_GOTPCREL: 216 checkIs32(Ctx, Loc, Type); 217 // Older versions of ld.bfd/ld.gold/lld 218 // do not support GOTPCRELX/REX_GOTPCRELX/CODE_4_GOTPCRELX, 219 // and we want to keep back-compatibility. 220 if (!Ctx.getTargetOptions()->X86RelaxRelocations) 221 return ELF::R_X86_64_GOTPCREL; 222 switch (unsigned(Kind)) { 223 default: 224 return ELF::R_X86_64_GOTPCREL; 225 case X86::reloc_riprel_4byte_relax: 226 return ELF::R_X86_64_GOTPCRELX; 227 case X86::reloc_riprel_4byte_relax_rex: 228 case X86::reloc_riprel_4byte_movq_load: 229 return ELF::R_X86_64_REX_GOTPCRELX; 230 case X86::reloc_riprel_4byte_relax_rex2: 231 case X86::reloc_riprel_4byte_movq_load_rex2: 232 return ELF::R_X86_64_CODE_4_GOTPCRELX; 233 } 234 llvm_unreachable("unexpected relocation type!"); 235 case MCSymbolRefExpr::VK_GOTPCREL_NORELAX: 236 checkIs32(Ctx, Loc, Type); 237 return ELF::R_X86_64_GOTPCREL; 238 case MCSymbolRefExpr::VK_X86_PLTOFF: 239 checkIs64(Ctx, Loc, Type); 240 return ELF::R_X86_64_PLTOFF64; 241 } 242 } 243 244 enum X86_32RelType { RT32_NONE, RT32_32, RT32_16, RT32_8 }; 245 246 static unsigned getRelocType32(MCContext &Ctx, SMLoc Loc, 247 MCSymbolRefExpr::VariantKind Modifier, 248 X86_32RelType Type, bool IsPCRel, 249 MCFixupKind Kind) { 250 switch (Modifier) { 251 default: 252 llvm_unreachable("Unimplemented"); 253 case MCSymbolRefExpr::VK_None: 254 case MCSymbolRefExpr::VK_X86_ABS8: 255 switch (Type) { 256 case RT32_NONE: 257 if (Modifier == MCSymbolRefExpr::VK_None) 258 return ELF::R_386_NONE; 259 llvm_unreachable("Unimplemented"); 260 case RT32_32: 261 return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32; 262 case RT32_16: 263 return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16; 264 case RT32_8: 265 return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8; 266 } 267 llvm_unreachable("unexpected relocation type!"); 268 case MCSymbolRefExpr::VK_GOT: 269 if (Type != RT32_32) 270 break; 271 if (IsPCRel) 272 return ELF::R_386_GOTPC; 273 // Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we 274 // want to maintain compatibility. 275 if (!Ctx.getTargetOptions()->X86RelaxRelocations) 276 return ELF::R_386_GOT32; 277 278 return Kind == MCFixupKind(X86::reloc_signed_4byte_relax) 279 ? ELF::R_386_GOT32X 280 : ELF::R_386_GOT32; 281 case MCSymbolRefExpr::VK_GOTOFF: 282 assert(!IsPCRel); 283 if (Type != RT32_32) 284 break; 285 return ELF::R_386_GOTOFF; 286 case MCSymbolRefExpr::VK_TLSCALL: 287 return ELF::R_386_TLS_DESC_CALL; 288 case MCSymbolRefExpr::VK_TLSDESC: 289 return ELF::R_386_TLS_GOTDESC; 290 case MCSymbolRefExpr::VK_TPOFF: 291 if (Type != RT32_32) 292 break; 293 assert(!IsPCRel); 294 return ELF::R_386_TLS_LE_32; 295 case MCSymbolRefExpr::VK_DTPOFF: 296 if (Type != RT32_32) 297 break; 298 assert(!IsPCRel); 299 return ELF::R_386_TLS_LDO_32; 300 case MCSymbolRefExpr::VK_TLSGD: 301 if (Type != RT32_32) 302 break; 303 assert(!IsPCRel); 304 return ELF::R_386_TLS_GD; 305 case MCSymbolRefExpr::VK_GOTTPOFF: 306 if (Type != RT32_32) 307 break; 308 assert(!IsPCRel); 309 return ELF::R_386_TLS_IE_32; 310 case MCSymbolRefExpr::VK_PLT: 311 if (Type != RT32_32) 312 break; 313 return ELF::R_386_PLT32; 314 case MCSymbolRefExpr::VK_INDNTPOFF: 315 if (Type != RT32_32) 316 break; 317 assert(!IsPCRel); 318 return ELF::R_386_TLS_IE; 319 case MCSymbolRefExpr::VK_NTPOFF: 320 if (Type != RT32_32) 321 break; 322 assert(!IsPCRel); 323 return ELF::R_386_TLS_LE; 324 case MCSymbolRefExpr::VK_GOTNTPOFF: 325 if (Type != RT32_32) 326 break; 327 assert(!IsPCRel); 328 return ELF::R_386_TLS_GOTIE; 329 case MCSymbolRefExpr::VK_TLSLDM: 330 if (Type != RT32_32) 331 break; 332 assert(!IsPCRel); 333 return ELF::R_386_TLS_LDM; 334 } 335 Ctx.reportError(Loc, "unsupported relocation type"); 336 return ELF::R_386_NONE; 337 } 338 339 unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, 340 const MCFixup &Fixup, 341 bool IsPCRel) const { 342 MCFixupKind Kind = Fixup.getKind(); 343 if (Kind >= FirstLiteralRelocationKind) 344 return Kind - FirstLiteralRelocationKind; 345 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); 346 X86_64RelType Type = getType64(Kind, Modifier, IsPCRel); 347 if (getEMachine() == ELF::EM_X86_64) 348 return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel, Kind); 349 350 assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) && 351 "Unsupported ELF machine type."); 352 353 X86_32RelType RelType = RT32_NONE; 354 switch (Type) { 355 case RT64_NONE: 356 break; 357 case RT64_64: 358 Ctx.reportError(Fixup.getLoc(), "unsupported relocation type"); 359 return ELF::R_386_NONE; 360 case RT64_32: 361 case RT64_32S: 362 RelType = RT32_32; 363 break; 364 case RT64_16: 365 RelType = RT32_16; 366 break; 367 case RT64_8: 368 RelType = RT32_8; 369 break; 370 } 371 return getRelocType32(Ctx, Fixup.getLoc(), Modifier, RelType, IsPCRel, Kind); 372 } 373 374 std::unique_ptr<MCObjectTargetWriter> 375 llvm::createX86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine) { 376 return std::make_unique<X86ELFObjectWriter>(IsELF64, OSABI, EMachine); 377 } 378