1 //===-- X86ELFObjectWriter.cpp - X86 ELF Writer ---------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "MCTargetDesc/X86FixupKinds.h" 11 #include "MCTargetDesc/X86MCTargetDesc.h" 12 #include "llvm/MC/MCContext.h" 13 #include "llvm/MC/MCELFObjectWriter.h" 14 #include "llvm/MC/MCExpr.h" 15 #include "llvm/MC/MCValue.h" 16 #include "llvm/Support/ELF.h" 17 #include "llvm/Support/ErrorHandling.h" 18 19 using namespace llvm; 20 21 namespace { 22 class X86ELFObjectWriter : public MCELFObjectTargetWriter { 23 public: 24 X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine); 25 26 ~X86ELFObjectWriter() override; 27 28 protected: 29 unsigned getRelocType(MCContext &Ctx, const MCValue &Target, 30 const MCFixup &Fixup, bool IsPCRel) const override; 31 }; 32 } 33 34 X86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, 35 uint16_t EMachine) 36 : MCELFObjectTargetWriter(IsELF64, OSABI, EMachine, 37 // Only i386 and IAMCU use Rel instead of RelA. 38 /*HasRelocationAddend*/ 39 (EMachine != ELF::EM_386) && 40 (EMachine != ELF::EM_IAMCU)) {} 41 42 X86ELFObjectWriter::~X86ELFObjectWriter() 43 {} 44 45 enum X86_64RelType { RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 }; 46 47 static X86_64RelType getType64(unsigned Kind, 48 MCSymbolRefExpr::VariantKind &Modifier, 49 bool &IsPCRel) { 50 switch (Kind) { 51 default: 52 llvm_unreachable("Unimplemented"); 53 case X86::reloc_global_offset_table8: 54 Modifier = MCSymbolRefExpr::VK_GOT; 55 IsPCRel = true; 56 return RT64_64; 57 case FK_Data_8: 58 return RT64_64; 59 case X86::reloc_signed_4byte: 60 if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel) 61 return RT64_32S; 62 return RT64_32; 63 case X86::reloc_global_offset_table: 64 Modifier = MCSymbolRefExpr::VK_GOT; 65 IsPCRel = true; 66 return RT64_32; 67 case FK_Data_4: 68 case FK_PCRel_4: 69 case X86::reloc_riprel_4byte: 70 case X86::reloc_riprel_4byte_movq_load: 71 return RT64_32; 72 case FK_PCRel_2: 73 case FK_Data_2: 74 return RT64_16; 75 case FK_PCRel_1: 76 case FK_Data_1: 77 return RT64_8; 78 } 79 } 80 81 static void checkIs32(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) { 82 if (Type != RT64_32) 83 Ctx.reportError(Loc, 84 "32 bit reloc applied to a field with a different size"); 85 } 86 87 static unsigned getRelocType64(MCContext &Ctx, SMLoc Loc, 88 MCSymbolRefExpr::VariantKind Modifier, 89 X86_64RelType Type, bool IsPCRel) { 90 switch (Modifier) { 91 default: 92 llvm_unreachable("Unimplemented"); 93 case MCSymbolRefExpr::VK_None: 94 switch (Type) { 95 case RT64_64: 96 return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64; 97 case RT64_32: 98 return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32; 99 case RT64_32S: 100 return ELF::R_X86_64_32S; 101 case RT64_16: 102 return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16; 103 case RT64_8: 104 return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8; 105 } 106 case MCSymbolRefExpr::VK_GOT: 107 switch (Type) { 108 case RT64_64: 109 return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64; 110 case RT64_32: 111 return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32; 112 case RT64_32S: 113 case RT64_16: 114 case RT64_8: 115 llvm_unreachable("Unimplemented"); 116 } 117 case MCSymbolRefExpr::VK_GOTOFF: 118 assert(Type == RT64_64); 119 assert(!IsPCRel); 120 return ELF::R_X86_64_GOTOFF64; 121 case MCSymbolRefExpr::VK_TPOFF: 122 assert(!IsPCRel); 123 switch (Type) { 124 case RT64_64: 125 return ELF::R_X86_64_TPOFF64; 126 case RT64_32: 127 return ELF::R_X86_64_TPOFF32; 128 case RT64_32S: 129 case RT64_16: 130 case RT64_8: 131 llvm_unreachable("Unimplemented"); 132 } 133 case MCSymbolRefExpr::VK_DTPOFF: 134 assert(!IsPCRel); 135 switch (Type) { 136 case RT64_64: 137 return ELF::R_X86_64_DTPOFF64; 138 case RT64_32: 139 return ELF::R_X86_64_DTPOFF32; 140 case RT64_32S: 141 case RT64_16: 142 case RT64_8: 143 llvm_unreachable("Unimplemented"); 144 } 145 case MCSymbolRefExpr::VK_SIZE: 146 assert(!IsPCRel); 147 switch (Type) { 148 case RT64_64: 149 return ELF::R_X86_64_SIZE64; 150 case RT64_32: 151 return ELF::R_X86_64_SIZE32; 152 case RT64_32S: 153 case RT64_16: 154 case RT64_8: 155 llvm_unreachable("Unimplemented"); 156 } 157 case MCSymbolRefExpr::VK_TLSGD: 158 checkIs32(Ctx, Loc, Type); 159 return ELF::R_X86_64_TLSGD; 160 case MCSymbolRefExpr::VK_GOTTPOFF: 161 checkIs32(Ctx, Loc, Type); 162 return ELF::R_X86_64_GOTTPOFF; 163 case MCSymbolRefExpr::VK_TLSLD: 164 checkIs32(Ctx, Loc, Type); 165 return ELF::R_X86_64_TLSLD; 166 case MCSymbolRefExpr::VK_PLT: 167 checkIs32(Ctx, Loc, Type); 168 return ELF::R_X86_64_PLT32; 169 case MCSymbolRefExpr::VK_GOTPCREL: 170 checkIs32(Ctx, Loc, Type); 171 return ELF::R_X86_64_GOTPCREL; 172 } 173 } 174 175 enum X86_32RelType { RT32_32, RT32_16, RT32_8 }; 176 177 static X86_32RelType getType32(X86_64RelType T) { 178 switch (T) { 179 case RT64_64: 180 llvm_unreachable("Unimplemented"); 181 case RT64_32: 182 case RT64_32S: 183 return RT32_32; 184 case RT64_16: 185 return RT32_16; 186 case RT64_8: 187 return RT32_8; 188 } 189 llvm_unreachable("unexpected relocation type!"); 190 } 191 192 static unsigned getRelocType32(MCSymbolRefExpr::VariantKind Modifier, 193 X86_32RelType Type, bool IsPCRel) { 194 switch (Modifier) { 195 default: 196 llvm_unreachable("Unimplemented"); 197 case MCSymbolRefExpr::VK_None: 198 switch (Type) { 199 case RT32_32: 200 return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32; 201 case RT32_16: 202 return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16; 203 case RT32_8: 204 return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8; 205 } 206 case MCSymbolRefExpr::VK_GOT: 207 assert(Type == RT32_32); 208 return IsPCRel ? ELF::R_386_GOTPC : ELF::R_386_GOT32; 209 case MCSymbolRefExpr::VK_GOTOFF: 210 assert(Type == RT32_32); 211 assert(!IsPCRel); 212 return ELF::R_386_GOTOFF; 213 case MCSymbolRefExpr::VK_TPOFF: 214 assert(Type == RT32_32); 215 assert(!IsPCRel); 216 return ELF::R_386_TLS_LE_32; 217 case MCSymbolRefExpr::VK_DTPOFF: 218 assert(Type == RT32_32); 219 assert(!IsPCRel); 220 return ELF::R_386_TLS_LDO_32; 221 case MCSymbolRefExpr::VK_TLSGD: 222 assert(Type == RT32_32); 223 assert(!IsPCRel); 224 return ELF::R_386_TLS_GD; 225 case MCSymbolRefExpr::VK_GOTTPOFF: 226 assert(Type == RT32_32); 227 assert(!IsPCRel); 228 return ELF::R_386_TLS_IE_32; 229 case MCSymbolRefExpr::VK_PLT: 230 assert(Type == RT32_32); 231 return ELF::R_386_PLT32; 232 case MCSymbolRefExpr::VK_INDNTPOFF: 233 assert(Type == RT32_32); 234 assert(!IsPCRel); 235 return ELF::R_386_TLS_IE; 236 case MCSymbolRefExpr::VK_NTPOFF: 237 assert(Type == RT32_32); 238 assert(!IsPCRel); 239 return ELF::R_386_TLS_LE; 240 case MCSymbolRefExpr::VK_GOTNTPOFF: 241 assert(Type == RT32_32); 242 assert(!IsPCRel); 243 return ELF::R_386_TLS_GOTIE; 244 case MCSymbolRefExpr::VK_TLSLDM: 245 assert(Type == RT32_32); 246 assert(!IsPCRel); 247 return ELF::R_386_TLS_LDM; 248 } 249 } 250 251 unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, 252 const MCFixup &Fixup, 253 bool IsPCRel) const { 254 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); 255 X86_64RelType Type = getType64(Fixup.getKind(), Modifier, IsPCRel); 256 if (getEMachine() == ELF::EM_X86_64) 257 return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel); 258 259 assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) && 260 "Unsupported ELF machine type."); 261 return getRelocType32(Modifier, getType32(Type), IsPCRel); 262 } 263 264 MCObjectWriter *llvm::createX86ELFObjectWriter(raw_pwrite_stream &OS, 265 bool IsELF64, uint8_t OSABI, 266 uint16_t EMachine) { 267 MCELFObjectTargetWriter *MOTW = 268 new X86ELFObjectWriter(IsELF64, OSABI, EMachine); 269 return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/true); 270 } 271