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