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