404 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "MCTargetDesc/X86FixupKinds.h"10#include "MCTargetDesc/X86MCAsmInfo.h"11#include "MCTargetDesc/X86MCTargetDesc.h"12#include "llvm/BinaryFormat/ELF.h"13#include "llvm/MC/MCAsmInfo.h"14#include "llvm/MC/MCContext.h"15#include "llvm/MC/MCELFObjectWriter.h"16#include "llvm/MC/MCExpr.h"17#include "llvm/MC/MCFixup.h"18#include "llvm/MC/MCObjectWriter.h"19#include "llvm/MC/MCValue.h"20#include "llvm/Support/ErrorHandling.h"21#include <cassert>22#include <cstdint>23 24using namespace llvm;25 26namespace {27enum X86_32RelType { RT32_NONE, RT32_32, RT32_16, RT32_8 };28enum X86_64RelType { RT64_NONE, RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 };29 30class X86ELFObjectWriter : public MCELFObjectTargetWriter {31public:32 X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine);33 ~X86ELFObjectWriter() override = default;34 35protected:36 unsigned getRelocType(const MCFixup &, const MCValue &,37 bool IsPCRel) const override;38 bool needsRelocateWithSymbol(const MCValue &, unsigned Type) const override;39 40 void checkIs32(SMLoc Loc, X86_64RelType Type) const;41 void checkIs64(SMLoc Loc, X86_64RelType Type) const;42 unsigned getRelocType32(SMLoc Loc, X86::Specifier Specifier,43 X86_32RelType Type, bool IsPCRel,44 MCFixupKind Kind) const;45 unsigned getRelocType64(SMLoc Loc, X86::Specifier Specifier,46 X86_64RelType Type, bool IsPCRel,47 MCFixupKind Kind) const;48};49 50} // end anonymous namespace51 52X86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI,53 uint16_t EMachine)54 : MCELFObjectTargetWriter(IsELF64, OSABI, EMachine,55 // Only i386 and IAMCU use Rel instead of RelA.56 /*HasRelocationAddend*/57 (EMachine != ELF::EM_386) &&58 (EMachine != ELF::EM_IAMCU)) {}59 60static X86_64RelType getType64(MCFixupKind Kind, X86::Specifier &Specifier,61 bool &IsPCRel) {62 switch (unsigned(Kind)) {63 default:64 llvm_unreachable("Unimplemented");65 case FK_NONE:66 return RT64_NONE;67 case FK_Data_8:68 return RT64_64;69 case X86::reloc_signed_4byte:70 case X86::reloc_signed_4byte_relax:71 if (Specifier == X86::S_None && !IsPCRel)72 return RT64_32S;73 return RT64_32;74 case X86::reloc_global_offset_table:75 Specifier = X86::S_GOT;76 IsPCRel = true;77 return RT64_32;78 case FK_Data_4:79 case X86::reloc_riprel_4byte:80 case X86::reloc_riprel_4byte_relax:81 case X86::reloc_riprel_4byte_relax_rex:82 case X86::reloc_riprel_4byte_relax_rex2:83 case X86::reloc_riprel_4byte_movq_load:84 case X86::reloc_riprel_4byte_movq_load_rex2:85 case X86::reloc_riprel_4byte_relax_evex:86 return RT64_32;87 case X86::reloc_branch_4byte_pcrel:88 Specifier = X86::S_PLT;89 return RT64_32;90 case FK_Data_2:91 return RT64_16;92 case FK_Data_1:93 return RT64_8;94 }95}96 97void X86ELFObjectWriter::checkIs32(SMLoc Loc, X86_64RelType Type) const {98 if (Type != RT64_32)99 reportError(Loc, "32 bit reloc applied to a field with a different size");100}101 102void X86ELFObjectWriter::checkIs64(SMLoc Loc, X86_64RelType Type) const {103 if (Type != RT64_64)104 reportError(Loc, "64 bit reloc applied to a field with a different size");105}106 107unsigned X86ELFObjectWriter::getRelocType64(SMLoc Loc, X86::Specifier Specifier,108 X86_64RelType Type, bool IsPCRel,109 MCFixupKind Kind) const {110 switch (Specifier) {111 default:112 llvm_unreachable("Unimplemented");113 case X86::S_None:114 case X86::S_ABS8:115 switch (Type) {116 case RT64_NONE:117 if (Specifier == X86::S_None)118 return ELF::R_X86_64_NONE;119 llvm_unreachable("Unimplemented");120 case RT64_64:121 return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64;122 case RT64_32:123 return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32;124 case RT64_32S:125 return ELF::R_X86_64_32S;126 case RT64_16:127 return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16;128 case RT64_8:129 return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8;130 }131 llvm_unreachable("unexpected relocation type!");132 case X86::S_GOT:133 switch (Type) {134 case RT64_64:135 return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64;136 case RT64_32:137 return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32;138 case RT64_32S:139 case RT64_16:140 case RT64_8:141 case RT64_NONE:142 llvm_unreachable("Unimplemented");143 }144 llvm_unreachable("unexpected relocation type!");145 case X86::S_GOTOFF:146 assert(!IsPCRel);147 if (Type != RT64_64)148 reportError(Loc, "unsupported relocation type");149 return ELF::R_X86_64_GOTOFF64;150 case X86::S_TPOFF:151 assert(!IsPCRel);152 switch (Type) {153 case RT64_64:154 return ELF::R_X86_64_TPOFF64;155 case RT64_32:156 return ELF::R_X86_64_TPOFF32;157 case RT64_32S:158 case RT64_16:159 case RT64_8:160 case RT64_NONE:161 llvm_unreachable("Unimplemented");162 }163 llvm_unreachable("unexpected relocation type!");164 case X86::S_DTPOFF:165 assert(!IsPCRel);166 switch (Type) {167 case RT64_64:168 return ELF::R_X86_64_DTPOFF64;169 case RT64_32:170 return ELF::R_X86_64_DTPOFF32;171 case RT64_32S:172 case RT64_16:173 case RT64_8:174 case RT64_NONE:175 llvm_unreachable("Unimplemented");176 }177 llvm_unreachable("unexpected relocation type!");178 case X86::S_SIZE:179 assert(!IsPCRel);180 switch (Type) {181 case RT64_64:182 return ELF::R_X86_64_SIZE64;183 case RT64_32:184 return ELF::R_X86_64_SIZE32;185 case RT64_32S:186 case RT64_16:187 case RT64_8:188 case RT64_NONE:189 llvm_unreachable("Unimplemented");190 }191 llvm_unreachable("unexpected relocation type!");192 case X86::S_TLSCALL:193 return ELF::R_X86_64_TLSDESC_CALL;194 case X86::S_TLSDESC:195 return ((unsigned)Kind == X86::reloc_riprel_4byte_relax_rex2)196 ? ELF::R_X86_64_CODE_4_GOTPC32_TLSDESC197 : ELF::R_X86_64_GOTPC32_TLSDESC;198 case X86::S_TLSGD:199 checkIs32(Loc, Type);200 return ELF::R_X86_64_TLSGD;201 case X86::S_GOTTPOFF:202 checkIs32(Loc, Type);203 if ((unsigned)Kind == X86::reloc_riprel_4byte_movq_load_rex2 ||204 (unsigned)Kind == X86::reloc_riprel_4byte_relax_rex2)205 return ELF::R_X86_64_CODE_4_GOTTPOFF;206 else if ((unsigned)Kind == X86::reloc_riprel_4byte_relax_evex)207 return ELF::R_X86_64_CODE_6_GOTTPOFF;208 return ELF::R_X86_64_GOTTPOFF;209 case X86::S_TLSLD:210 checkIs32(Loc, Type);211 return ELF::R_X86_64_TLSLD;212 case X86::S_PLT:213 checkIs32(Loc, Type);214 return ELF::R_X86_64_PLT32;215 case X86::S_GOTPCREL:216 checkIs32(Loc, Type);217 // Older versions of ld.bfd/ld.gold/lld218 // do not support GOTPCRELX/REX_GOTPCRELX/CODE_4_GOTPCRELX,219 // and we want to keep back-compatibility.220 if (!getContext().getTargetOptions()->X86RelaxRelocations)221 return ELF::R_X86_64_GOTPCREL;222 switch (unsigned(Kind)) {223 default:224 return ELF::R_X86_64_GOTPCREL;225 case X86::reloc_riprel_4byte_relax:226 return ELF::R_X86_64_GOTPCRELX;227 case X86::reloc_riprel_4byte_relax_rex:228 case X86::reloc_riprel_4byte_movq_load:229 return ELF::R_X86_64_REX_GOTPCRELX;230 case X86::reloc_riprel_4byte_relax_rex2:231 case X86::reloc_riprel_4byte_movq_load_rex2:232 return ELF::R_X86_64_CODE_4_GOTPCRELX;233 }234 llvm_unreachable("unexpected relocation type!");235 case X86::S_GOTPCREL_NORELAX:236 checkIs32(Loc, Type);237 return ELF::R_X86_64_GOTPCREL;238 case X86::S_PLTOFF:239 checkIs64(Loc, Type);240 return ELF::R_X86_64_PLTOFF64;241 }242}243 244unsigned X86ELFObjectWriter::getRelocType32(SMLoc Loc, X86::Specifier Specifier,245 X86_32RelType Type, bool IsPCRel,246 MCFixupKind Kind) const {247 switch (Specifier) {248 default:249 llvm_unreachable("Unimplemented");250 case X86::S_None:251 case X86::S_ABS8:252 switch (Type) {253 case RT32_NONE:254 if (Specifier == X86::S_None)255 return ELF::R_386_NONE;256 llvm_unreachable("Unimplemented");257 case RT32_32:258 return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32;259 case RT32_16:260 return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16;261 case RT32_8:262 return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8;263 }264 llvm_unreachable("unexpected relocation type!");265 case X86::S_GOT:266 if (Type != RT32_32)267 break;268 if (IsPCRel)269 return ELF::R_386_GOTPC;270 // Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we271 // want to maintain compatibility.272 if (!getContext().getTargetOptions()->X86RelaxRelocations)273 return ELF::R_386_GOT32;274 275 return Kind == X86::reloc_signed_4byte_relax ? ELF::R_386_GOT32X276 : ELF::R_386_GOT32;277 case X86::S_GOTOFF:278 assert(!IsPCRel);279 if (Type != RT32_32)280 break;281 return ELF::R_386_GOTOFF;282 case X86::S_TLSCALL:283 return ELF::R_386_TLS_DESC_CALL;284 case X86::S_TLSDESC:285 return ELF::R_386_TLS_GOTDESC;286 case X86::S_TPOFF:287 if (Type != RT32_32)288 break;289 assert(!IsPCRel);290 return ELF::R_386_TLS_LE_32;291 case X86::S_DTPOFF:292 if (Type != RT32_32)293 break;294 assert(!IsPCRel);295 return ELF::R_386_TLS_LDO_32;296 case X86::S_TLSGD:297 if (Type != RT32_32)298 break;299 assert(!IsPCRel);300 return ELF::R_386_TLS_GD;301 case X86::S_GOTTPOFF:302 if (Type != RT32_32)303 break;304 assert(!IsPCRel);305 return ELF::R_386_TLS_IE_32;306 case X86::S_PLT:307 if (Type != RT32_32)308 break;309 return ELF::R_386_PLT32;310 case X86::S_INDNTPOFF:311 if (Type != RT32_32)312 break;313 assert(!IsPCRel);314 return ELF::R_386_TLS_IE;315 case X86::S_NTPOFF:316 if (Type != RT32_32)317 break;318 assert(!IsPCRel);319 return ELF::R_386_TLS_LE;320 case X86::S_GOTNTPOFF:321 if (Type != RT32_32)322 break;323 assert(!IsPCRel);324 return ELF::R_386_TLS_GOTIE;325 case X86::S_TLSLDM:326 if (Type != RT32_32)327 break;328 assert(!IsPCRel);329 return ELF::R_386_TLS_LDM;330 }331 reportError(Loc, "unsupported relocation type");332 return ELF::R_386_NONE;333}334 335unsigned X86ELFObjectWriter::getRelocType(const MCFixup &Fixup,336 const MCValue &Target,337 bool IsPCRel) const {338 MCFixupKind Kind = Fixup.getKind();339 auto Specifier = X86::Specifier(Target.getSpecifier());340 switch (Specifier) {341 case X86::S_GOTTPOFF:342 case X86::S_INDNTPOFF:343 case X86::S_NTPOFF:344 case X86::S_GOTNTPOFF:345 case X86::S_TLSCALL:346 case X86::S_TLSDESC:347 case X86::S_TLSGD:348 case X86::S_TLSLD:349 case X86::S_TLSLDM:350 case X86::S_TPOFF:351 case X86::S_DTPOFF:352 if (auto *S = const_cast<MCSymbol *>(Target.getAddSym()))353 static_cast<MCSymbolELF *>(S)->setType(ELF::STT_TLS);354 break;355 default:356 break;357 }358 359 X86_64RelType Type = getType64(Kind, Specifier, IsPCRel);360 if (getEMachine() == ELF::EM_X86_64)361 return getRelocType64(Fixup.getLoc(), Specifier, Type, IsPCRel, Kind);362 363 assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) &&364 "Unsupported ELF machine type.");365 366 X86_32RelType RelType = RT32_NONE;367 switch (Type) {368 case RT64_NONE:369 break;370 case RT64_64:371 reportError(Fixup.getLoc(), "unsupported relocation type");372 return ELF::R_386_NONE;373 case RT64_32:374 case RT64_32S:375 RelType = RT32_32;376 break;377 case RT64_16:378 RelType = RT32_16;379 break;380 case RT64_8:381 RelType = RT32_8;382 break;383 }384 return getRelocType32(Fixup.getLoc(), Specifier, RelType, IsPCRel, Kind);385}386 387bool X86ELFObjectWriter::needsRelocateWithSymbol(const MCValue &V,388 unsigned Type) const {389 switch (V.getSpecifier()) {390 case X86::S_GOT:391 case X86::S_PLT:392 case X86::S_GOTPCREL:393 case X86::S_GOTPCREL_NORELAX:394 return true;395 default:396 return false;397 }398}399 400std::unique_ptr<MCObjectTargetWriter>401llvm::createX86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine) {402 return std::make_unique<X86ELFObjectWriter>(IsELF64, OSABI, EMachine);403}404