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