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 unsigned getRelocType32(MCContext &Ctx, 233 MCSymbolRefExpr::VariantKind Modifier, 234 X86_32RelType Type, bool IsPCRel, 235 MCFixupKind Kind) { 236 switch (Modifier) { 237 default: 238 llvm_unreachable("Unimplemented"); 239 case MCSymbolRefExpr::VK_None: 240 case MCSymbolRefExpr::VK_X86_ABS8: 241 switch (Type) { 242 case RT32_NONE: 243 if (Modifier == MCSymbolRefExpr::VK_None) 244 return ELF::R_386_NONE; 245 llvm_unreachable("Unimplemented"); 246 case RT32_32: 247 return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32; 248 case RT32_16: 249 return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16; 250 case RT32_8: 251 return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8; 252 } 253 llvm_unreachable("unexpected relocation type!"); 254 case MCSymbolRefExpr::VK_GOT: 255 assert(Type == RT32_32); 256 if (IsPCRel) 257 return ELF::R_386_GOTPC; 258 // Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we 259 // want to maintain compatibility. 260 if (!Ctx.getAsmInfo()->canRelaxRelocations()) 261 return ELF::R_386_GOT32; 262 263 return Kind == MCFixupKind(X86::reloc_signed_4byte_relax) 264 ? ELF::R_386_GOT32X 265 : ELF::R_386_GOT32; 266 case MCSymbolRefExpr::VK_GOTOFF: 267 assert(Type == RT32_32); 268 assert(!IsPCRel); 269 return ELF::R_386_GOTOFF; 270 case MCSymbolRefExpr::VK_TLSCALL: 271 return ELF::R_386_TLS_DESC_CALL; 272 case MCSymbolRefExpr::VK_TLSDESC: 273 return ELF::R_386_TLS_GOTDESC; 274 case MCSymbolRefExpr::VK_TPOFF: 275 assert(Type == RT32_32); 276 assert(!IsPCRel); 277 return ELF::R_386_TLS_LE_32; 278 case MCSymbolRefExpr::VK_DTPOFF: 279 assert(Type == RT32_32); 280 assert(!IsPCRel); 281 return ELF::R_386_TLS_LDO_32; 282 case MCSymbolRefExpr::VK_TLSGD: 283 assert(Type == RT32_32); 284 assert(!IsPCRel); 285 return ELF::R_386_TLS_GD; 286 case MCSymbolRefExpr::VK_GOTTPOFF: 287 assert(Type == RT32_32); 288 assert(!IsPCRel); 289 return ELF::R_386_TLS_IE_32; 290 case MCSymbolRefExpr::VK_PLT: 291 assert(Type == RT32_32); 292 return ELF::R_386_PLT32; 293 case MCSymbolRefExpr::VK_INDNTPOFF: 294 assert(Type == RT32_32); 295 assert(!IsPCRel); 296 return ELF::R_386_TLS_IE; 297 case MCSymbolRefExpr::VK_NTPOFF: 298 assert(Type == RT32_32); 299 assert(!IsPCRel); 300 return ELF::R_386_TLS_LE; 301 case MCSymbolRefExpr::VK_GOTNTPOFF: 302 assert(Type == RT32_32); 303 assert(!IsPCRel); 304 return ELF::R_386_TLS_GOTIE; 305 case MCSymbolRefExpr::VK_TLSLDM: 306 assert(Type == RT32_32); 307 assert(!IsPCRel); 308 return ELF::R_386_TLS_LDM; 309 } 310 } 311 312 unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, 313 const MCFixup &Fixup, 314 bool IsPCRel) const { 315 MCFixupKind Kind = Fixup.getKind(); 316 if (Kind >= FirstLiteralRelocationKind) 317 return Kind - FirstLiteralRelocationKind; 318 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); 319 X86_64RelType Type = getType64(Kind, Modifier, IsPCRel); 320 if (getEMachine() == ELF::EM_X86_64) 321 return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel, Kind); 322 323 assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) && 324 "Unsupported ELF machine type."); 325 326 X86_32RelType RelType = RT32_NONE; 327 switch (Type) { 328 case RT64_NONE: 329 break; 330 case RT64_64: 331 Ctx.reportError(Fixup.getLoc(), "unsupported relocation type"); 332 break; 333 case RT64_32: 334 case RT64_32S: 335 RelType = RT32_32; 336 break; 337 case RT64_16: 338 RelType = RT32_16; 339 break; 340 case RT64_8: 341 RelType = RT32_8; 342 break; 343 } 344 return getRelocType32(Ctx, Modifier, RelType, IsPCRel, Kind); 345 } 346 347 std::unique_ptr<MCObjectTargetWriter> 348 llvm::createX86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine) { 349 return std::make_unique<X86ELFObjectWriter>(IsELF64, OSABI, EMachine); 350 } 351