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(!IsPCRel); 144 if (Type != RT64_64) 145 Ctx.reportError(Loc, "unsupported relocation type"); 146 return ELF::R_X86_64_GOTOFF64; 147 case MCSymbolRefExpr::VK_TPOFF: 148 assert(!IsPCRel); 149 switch (Type) { 150 case RT64_64: 151 return ELF::R_X86_64_TPOFF64; 152 case RT64_32: 153 return ELF::R_X86_64_TPOFF32; 154 case RT64_32S: 155 case RT64_16: 156 case RT64_8: 157 case RT64_NONE: 158 llvm_unreachable("Unimplemented"); 159 } 160 llvm_unreachable("unexpected relocation type!"); 161 case MCSymbolRefExpr::VK_DTPOFF: 162 assert(!IsPCRel); 163 switch (Type) { 164 case RT64_64: 165 return ELF::R_X86_64_DTPOFF64; 166 case RT64_32: 167 return ELF::R_X86_64_DTPOFF32; 168 case RT64_32S: 169 case RT64_16: 170 case RT64_8: 171 case RT64_NONE: 172 llvm_unreachable("Unimplemented"); 173 } 174 llvm_unreachable("unexpected relocation type!"); 175 case MCSymbolRefExpr::VK_SIZE: 176 assert(!IsPCRel); 177 switch (Type) { 178 case RT64_64: 179 return ELF::R_X86_64_SIZE64; 180 case RT64_32: 181 return ELF::R_X86_64_SIZE32; 182 case RT64_32S: 183 case RT64_16: 184 case RT64_8: 185 case RT64_NONE: 186 llvm_unreachable("Unimplemented"); 187 } 188 llvm_unreachable("unexpected relocation type!"); 189 case MCSymbolRefExpr::VK_TLSCALL: 190 return ELF::R_X86_64_TLSDESC_CALL; 191 case MCSymbolRefExpr::VK_TLSDESC: 192 return ELF::R_X86_64_GOTPC32_TLSDESC; 193 case MCSymbolRefExpr::VK_TLSGD: 194 checkIs32(Ctx, Loc, Type); 195 return ELF::R_X86_64_TLSGD; 196 case MCSymbolRefExpr::VK_GOTTPOFF: 197 checkIs32(Ctx, Loc, Type); 198 return ELF::R_X86_64_GOTTPOFF; 199 case MCSymbolRefExpr::VK_TLSLD: 200 checkIs32(Ctx, Loc, Type); 201 return ELF::R_X86_64_TLSLD; 202 case MCSymbolRefExpr::VK_PLT: 203 checkIs32(Ctx, Loc, Type); 204 return ELF::R_X86_64_PLT32; 205 case MCSymbolRefExpr::VK_GOTPCREL: 206 checkIs32(Ctx, Loc, Type); 207 // Older versions of ld.bfd/ld.gold/lld 208 // do not support GOTPCRELX/REX_GOTPCRELX, 209 // and we want to keep back-compatibility. 210 if (!Ctx.getAsmInfo()->canRelaxRelocations()) 211 return ELF::R_X86_64_GOTPCREL; 212 switch (unsigned(Kind)) { 213 default: 214 return ELF::R_X86_64_GOTPCREL; 215 case X86::reloc_riprel_4byte_relax: 216 return ELF::R_X86_64_GOTPCRELX; 217 case X86::reloc_riprel_4byte_relax_rex: 218 case X86::reloc_riprel_4byte_movq_load: 219 return ELF::R_X86_64_REX_GOTPCRELX; 220 } 221 llvm_unreachable("unexpected relocation type!"); 222 case MCSymbolRefExpr::VK_GOTPCREL_NORELAX: 223 checkIs32(Ctx, Loc, Type); 224 return ELF::R_X86_64_GOTPCREL; 225 case MCSymbolRefExpr::VK_X86_PLTOFF: 226 checkIs64(Ctx, Loc, Type); 227 return ELF::R_X86_64_PLTOFF64; 228 } 229 } 230 231 enum X86_32RelType { RT32_NONE, RT32_32, RT32_16, RT32_8 }; 232 233 static unsigned getRelocType32(MCContext &Ctx, SMLoc Loc, 234 MCSymbolRefExpr::VariantKind Modifier, 235 X86_32RelType Type, bool IsPCRel, 236 MCFixupKind Kind) { 237 switch (Modifier) { 238 default: 239 llvm_unreachable("Unimplemented"); 240 case MCSymbolRefExpr::VK_None: 241 case MCSymbolRefExpr::VK_X86_ABS8: 242 switch (Type) { 243 case RT32_NONE: 244 if (Modifier == MCSymbolRefExpr::VK_None) 245 return ELF::R_386_NONE; 246 llvm_unreachable("Unimplemented"); 247 case RT32_32: 248 return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32; 249 case RT32_16: 250 return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16; 251 case RT32_8: 252 return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8; 253 } 254 llvm_unreachable("unexpected relocation type!"); 255 case MCSymbolRefExpr::VK_GOT: 256 if (Type != RT32_32) 257 break; 258 if (IsPCRel) 259 return ELF::R_386_GOTPC; 260 // Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we 261 // want to maintain compatibility. 262 if (!Ctx.getAsmInfo()->canRelaxRelocations()) 263 return ELF::R_386_GOT32; 264 265 return Kind == MCFixupKind(X86::reloc_signed_4byte_relax) 266 ? ELF::R_386_GOT32X 267 : ELF::R_386_GOT32; 268 case MCSymbolRefExpr::VK_GOTOFF: 269 assert(!IsPCRel); 270 if (Type != RT32_32) 271 break; 272 return ELF::R_386_GOTOFF; 273 case MCSymbolRefExpr::VK_TLSCALL: 274 return ELF::R_386_TLS_DESC_CALL; 275 case MCSymbolRefExpr::VK_TLSDESC: 276 return ELF::R_386_TLS_GOTDESC; 277 case MCSymbolRefExpr::VK_TPOFF: 278 if (Type != RT32_32) 279 break; 280 assert(!IsPCRel); 281 return ELF::R_386_TLS_LE_32; 282 case MCSymbolRefExpr::VK_DTPOFF: 283 if (Type != RT32_32) 284 break; 285 assert(!IsPCRel); 286 return ELF::R_386_TLS_LDO_32; 287 case MCSymbolRefExpr::VK_TLSGD: 288 if (Type != RT32_32) 289 break; 290 assert(!IsPCRel); 291 return ELF::R_386_TLS_GD; 292 case MCSymbolRefExpr::VK_GOTTPOFF: 293 if (Type != RT32_32) 294 break; 295 assert(!IsPCRel); 296 return ELF::R_386_TLS_IE_32; 297 case MCSymbolRefExpr::VK_PLT: 298 if (Type != RT32_32) 299 break; 300 return ELF::R_386_PLT32; 301 case MCSymbolRefExpr::VK_INDNTPOFF: 302 if (Type != RT32_32) 303 break; 304 assert(!IsPCRel); 305 return ELF::R_386_TLS_IE; 306 case MCSymbolRefExpr::VK_NTPOFF: 307 if (Type != RT32_32) 308 break; 309 assert(!IsPCRel); 310 return ELF::R_386_TLS_LE; 311 case MCSymbolRefExpr::VK_GOTNTPOFF: 312 if (Type != RT32_32) 313 break; 314 assert(!IsPCRel); 315 return ELF::R_386_TLS_GOTIE; 316 case MCSymbolRefExpr::VK_TLSLDM: 317 if (Type != RT32_32) 318 break; 319 assert(!IsPCRel); 320 return ELF::R_386_TLS_LDM; 321 } 322 Ctx.reportError(Loc, "unsupported relocation type"); 323 return ELF::R_386_NONE; 324 } 325 326 unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, 327 const MCFixup &Fixup, 328 bool IsPCRel) const { 329 MCFixupKind Kind = Fixup.getKind(); 330 if (Kind >= FirstLiteralRelocationKind) 331 return Kind - FirstLiteralRelocationKind; 332 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); 333 X86_64RelType Type = getType64(Kind, Modifier, IsPCRel); 334 if (getEMachine() == ELF::EM_X86_64) 335 return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel, Kind); 336 337 assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) && 338 "Unsupported ELF machine type."); 339 340 X86_32RelType RelType = RT32_NONE; 341 switch (Type) { 342 case RT64_NONE: 343 break; 344 case RT64_64: 345 Ctx.reportError(Fixup.getLoc(), "unsupported relocation type"); 346 return ELF::R_386_NONE; 347 case RT64_32: 348 case RT64_32S: 349 RelType = RT32_32; 350 break; 351 case RT64_16: 352 RelType = RT32_16; 353 break; 354 case RT64_8: 355 RelType = RT32_8; 356 break; 357 } 358 return getRelocType32(Ctx, Fixup.getLoc(), Modifier, RelType, IsPCRel, Kind); 359 } 360 361 std::unique_ptr<MCObjectTargetWriter> 362 llvm::createX86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine) { 363 return std::make_unique<X86ELFObjectWriter>(IsELF64, OSABI, EMachine); 364 } 365