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_X86_PLTOFF: 222 checkIs64(Ctx, Loc, Type); 223 return ELF::R_X86_64_PLTOFF64; 224 } 225 } 226 227 enum X86_32RelType { RT32_NONE, RT32_32, RT32_16, RT32_8 }; 228 229 static X86_32RelType getType32(X86_64RelType T) { 230 switch (T) { 231 case RT64_NONE: 232 return RT32_NONE; 233 case RT64_64: 234 llvm_unreachable("Unimplemented"); 235 case RT64_32: 236 case RT64_32S: 237 return RT32_32; 238 case RT64_16: 239 return RT32_16; 240 case RT64_8: 241 return RT32_8; 242 } 243 llvm_unreachable("unexpected relocation type!"); 244 } 245 246 static unsigned getRelocType32(MCContext &Ctx, 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 assert(Type == RT32_32); 270 if (IsPCRel) 271 return ELF::R_386_GOTPC; 272 // Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we 273 // want to maintain compatibility. 274 if (!Ctx.getAsmInfo()->canRelaxRelocations()) 275 return ELF::R_386_GOT32; 276 277 return Kind == MCFixupKind(X86::reloc_signed_4byte_relax) 278 ? ELF::R_386_GOT32X 279 : ELF::R_386_GOT32; 280 case MCSymbolRefExpr::VK_GOTOFF: 281 assert(Type == RT32_32); 282 assert(!IsPCRel); 283 return ELF::R_386_GOTOFF; 284 case MCSymbolRefExpr::VK_TLSCALL: 285 return ELF::R_386_TLS_DESC_CALL; 286 case MCSymbolRefExpr::VK_TLSDESC: 287 return ELF::R_386_TLS_GOTDESC; 288 case MCSymbolRefExpr::VK_TPOFF: 289 assert(Type == RT32_32); 290 assert(!IsPCRel); 291 return ELF::R_386_TLS_LE_32; 292 case MCSymbolRefExpr::VK_DTPOFF: 293 assert(Type == RT32_32); 294 assert(!IsPCRel); 295 return ELF::R_386_TLS_LDO_32; 296 case MCSymbolRefExpr::VK_TLSGD: 297 assert(Type == RT32_32); 298 assert(!IsPCRel); 299 return ELF::R_386_TLS_GD; 300 case MCSymbolRefExpr::VK_GOTTPOFF: 301 assert(Type == RT32_32); 302 assert(!IsPCRel); 303 return ELF::R_386_TLS_IE_32; 304 case MCSymbolRefExpr::VK_PLT: 305 assert(Type == RT32_32); 306 return ELF::R_386_PLT32; 307 case MCSymbolRefExpr::VK_INDNTPOFF: 308 assert(Type == RT32_32); 309 assert(!IsPCRel); 310 return ELF::R_386_TLS_IE; 311 case MCSymbolRefExpr::VK_NTPOFF: 312 assert(Type == RT32_32); 313 assert(!IsPCRel); 314 return ELF::R_386_TLS_LE; 315 case MCSymbolRefExpr::VK_GOTNTPOFF: 316 assert(Type == RT32_32); 317 assert(!IsPCRel); 318 return ELF::R_386_TLS_GOTIE; 319 case MCSymbolRefExpr::VK_TLSLDM: 320 assert(Type == RT32_32); 321 assert(!IsPCRel); 322 return ELF::R_386_TLS_LDM; 323 } 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 return getRelocType32(Ctx, Modifier, getType32(Type), IsPCRel, Kind); 340 } 341 342 std::unique_ptr<MCObjectTargetWriter> 343 llvm::createX86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine) { 344 return std::make_unique<X86ELFObjectWriter>(IsELF64, OSABI, EMachine); 345 } 346