brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.3 KiB · ea0abdd Raw
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