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