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(unsigned Kind, 50 MCSymbolRefExpr::VariantKind &Modifier, 51 bool &IsPCRel) { 52 switch (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 unsigned getRelocType64(MCContext &Ctx, SMLoc Loc, 98 MCSymbolRefExpr::VariantKind Modifier, 99 X86_64RelType Type, bool IsPCRel, 100 unsigned Kind) { 101 switch (Modifier) { 102 default: 103 llvm_unreachable("Unimplemented"); 104 case MCSymbolRefExpr::VK_None: 105 case MCSymbolRefExpr::VK_X86_ABS8: 106 switch (Type) { 107 case RT64_NONE: 108 if (Modifier == MCSymbolRefExpr::VK_None) 109 return ELF::R_X86_64_NONE; 110 llvm_unreachable("Unimplemented"); 111 case RT64_64: 112 return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64; 113 case RT64_32: 114 return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32; 115 case RT64_32S: 116 return ELF::R_X86_64_32S; 117 case RT64_16: 118 return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16; 119 case RT64_8: 120 return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8; 121 } 122 llvm_unreachable("unexpected relocation type!"); 123 case MCSymbolRefExpr::VK_GOT: 124 switch (Type) { 125 case RT64_64: 126 return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64; 127 case RT64_32: 128 return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32; 129 case RT64_32S: 130 case RT64_16: 131 case RT64_8: 132 case RT64_NONE: 133 llvm_unreachable("Unimplemented"); 134 } 135 llvm_unreachable("unexpected relocation type!"); 136 case MCSymbolRefExpr::VK_GOTOFF: 137 assert(Type == RT64_64); 138 assert(!IsPCRel); 139 return ELF::R_X86_64_GOTOFF64; 140 case MCSymbolRefExpr::VK_TPOFF: 141 assert(!IsPCRel); 142 switch (Type) { 143 case RT64_64: 144 return ELF::R_X86_64_TPOFF64; 145 case RT64_32: 146 return ELF::R_X86_64_TPOFF32; 147 case RT64_32S: 148 case RT64_16: 149 case RT64_8: 150 case RT64_NONE: 151 llvm_unreachable("Unimplemented"); 152 } 153 llvm_unreachable("unexpected relocation type!"); 154 case MCSymbolRefExpr::VK_DTPOFF: 155 assert(!IsPCRel); 156 switch (Type) { 157 case RT64_64: 158 return ELF::R_X86_64_DTPOFF64; 159 case RT64_32: 160 return ELF::R_X86_64_DTPOFF32; 161 case RT64_32S: 162 case RT64_16: 163 case RT64_8: 164 case RT64_NONE: 165 llvm_unreachable("Unimplemented"); 166 } 167 llvm_unreachable("unexpected relocation type!"); 168 case MCSymbolRefExpr::VK_SIZE: 169 assert(!IsPCRel); 170 switch (Type) { 171 case RT64_64: 172 return ELF::R_X86_64_SIZE64; 173 case RT64_32: 174 return ELF::R_X86_64_SIZE32; 175 case RT64_32S: 176 case RT64_16: 177 case RT64_8: 178 case RT64_NONE: 179 llvm_unreachable("Unimplemented"); 180 } 181 llvm_unreachable("unexpected relocation type!"); 182 case MCSymbolRefExpr::VK_TLSCALL: 183 return ELF::R_X86_64_TLSDESC_CALL; 184 case MCSymbolRefExpr::VK_TLSDESC: 185 return ELF::R_X86_64_GOTPC32_TLSDESC; 186 case MCSymbolRefExpr::VK_TLSGD: 187 checkIs32(Ctx, Loc, Type); 188 return ELF::R_X86_64_TLSGD; 189 case MCSymbolRefExpr::VK_GOTTPOFF: 190 checkIs32(Ctx, Loc, Type); 191 return ELF::R_X86_64_GOTTPOFF; 192 case MCSymbolRefExpr::VK_TLSLD: 193 checkIs32(Ctx, Loc, Type); 194 return ELF::R_X86_64_TLSLD; 195 case MCSymbolRefExpr::VK_PLT: 196 checkIs32(Ctx, Loc, Type); 197 return ELF::R_X86_64_PLT32; 198 case MCSymbolRefExpr::VK_GOTPCREL: 199 checkIs32(Ctx, Loc, Type); 200 // Older versions of ld.bfd/ld.gold/lld 201 // do not support GOTPCRELX/REX_GOTPCRELX, 202 // and we want to keep back-compatibility. 203 if (!Ctx.getAsmInfo()->canRelaxRelocations()) 204 return ELF::R_X86_64_GOTPCREL; 205 switch (Kind) { 206 default: 207 return ELF::R_X86_64_GOTPCREL; 208 case X86::reloc_riprel_4byte_relax: 209 return ELF::R_X86_64_GOTPCRELX; 210 case X86::reloc_riprel_4byte_relax_rex: 211 case X86::reloc_riprel_4byte_movq_load: 212 return ELF::R_X86_64_REX_GOTPCRELX; 213 } 214 llvm_unreachable("unexpected relocation type!"); 215 } 216 } 217 218 enum X86_32RelType { RT32_NONE, RT32_32, RT32_16, RT32_8 }; 219 220 static X86_32RelType getType32(X86_64RelType T) { 221 switch (T) { 222 case RT64_NONE: 223 return RT32_NONE; 224 case RT64_64: 225 llvm_unreachable("Unimplemented"); 226 case RT64_32: 227 case RT64_32S: 228 return RT32_32; 229 case RT64_16: 230 return RT32_16; 231 case RT64_8: 232 return RT32_8; 233 } 234 llvm_unreachable("unexpected relocation type!"); 235 } 236 237 static unsigned getRelocType32(MCContext &Ctx, 238 MCSymbolRefExpr::VariantKind Modifier, 239 X86_32RelType Type, bool IsPCRel, 240 unsigned Kind) { 241 switch (Modifier) { 242 default: 243 llvm_unreachable("Unimplemented"); 244 case MCSymbolRefExpr::VK_None: 245 case MCSymbolRefExpr::VK_X86_ABS8: 246 switch (Type) { 247 case RT32_NONE: 248 if (Modifier == MCSymbolRefExpr::VK_None) 249 return ELF::R_386_NONE; 250 llvm_unreachable("Unimplemented"); 251 case RT32_32: 252 return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32; 253 case RT32_16: 254 return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16; 255 case RT32_8: 256 return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8; 257 } 258 llvm_unreachable("unexpected relocation type!"); 259 case MCSymbolRefExpr::VK_GOT: 260 assert(Type == RT32_32); 261 if (IsPCRel) 262 return ELF::R_386_GOTPC; 263 // Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we 264 // want to maintain compatibility. 265 if (!Ctx.getAsmInfo()->canRelaxRelocations()) 266 return ELF::R_386_GOT32; 267 268 return Kind == X86::reloc_signed_4byte_relax ? ELF::R_386_GOT32X 269 : ELF::R_386_GOT32; 270 case MCSymbolRefExpr::VK_GOTOFF: 271 assert(Type == RT32_32); 272 assert(!IsPCRel); 273 return ELF::R_386_GOTOFF; 274 case MCSymbolRefExpr::VK_TLSCALL: 275 return ELF::R_386_TLS_DESC_CALL; 276 case MCSymbolRefExpr::VK_TLSDESC: 277 return ELF::R_386_TLS_GOTDESC; 278 case MCSymbolRefExpr::VK_TPOFF: 279 assert(Type == RT32_32); 280 assert(!IsPCRel); 281 return ELF::R_386_TLS_LE_32; 282 case MCSymbolRefExpr::VK_DTPOFF: 283 assert(Type == RT32_32); 284 assert(!IsPCRel); 285 return ELF::R_386_TLS_LDO_32; 286 case MCSymbolRefExpr::VK_TLSGD: 287 assert(Type == RT32_32); 288 assert(!IsPCRel); 289 return ELF::R_386_TLS_GD; 290 case MCSymbolRefExpr::VK_GOTTPOFF: 291 assert(Type == RT32_32); 292 assert(!IsPCRel); 293 return ELF::R_386_TLS_IE_32; 294 case MCSymbolRefExpr::VK_PLT: 295 assert(Type == RT32_32); 296 return ELF::R_386_PLT32; 297 case MCSymbolRefExpr::VK_INDNTPOFF: 298 assert(Type == RT32_32); 299 assert(!IsPCRel); 300 return ELF::R_386_TLS_IE; 301 case MCSymbolRefExpr::VK_NTPOFF: 302 assert(Type == RT32_32); 303 assert(!IsPCRel); 304 return ELF::R_386_TLS_LE; 305 case MCSymbolRefExpr::VK_GOTNTPOFF: 306 assert(Type == RT32_32); 307 assert(!IsPCRel); 308 return ELF::R_386_TLS_GOTIE; 309 case MCSymbolRefExpr::VK_TLSLDM: 310 assert(Type == RT32_32); 311 assert(!IsPCRel); 312 return ELF::R_386_TLS_LDM; 313 } 314 } 315 316 unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, 317 const MCFixup &Fixup, 318 bool IsPCRel) const { 319 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); 320 unsigned Kind = Fixup.getKind(); 321 X86_64RelType Type = getType64(Kind, Modifier, IsPCRel); 322 if (getEMachine() == ELF::EM_X86_64) 323 return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel, Kind); 324 325 assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) && 326 "Unsupported ELF machine type."); 327 return getRelocType32(Ctx, Modifier, getType32(Type), IsPCRel, Kind); 328 } 329 330 std::unique_ptr<MCObjectTargetWriter> 331 llvm::createX86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine) { 332 return llvm::make_unique<X86ELFObjectWriter>(IsELF64, OSABI, EMachine); 333 } 334