Path: blob/main/contrib/llvm-project/llvm/lib/Target/X86/MCTargetDesc/X86ELFObjectWriter.cpp
35294 views
//===-- X86ELFObjectWriter.cpp - X86 ELF Writer ---------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "MCTargetDesc/X86FixupKinds.h"9#include "MCTargetDesc/X86MCTargetDesc.h"10#include "llvm/BinaryFormat/ELF.h"11#include "llvm/MC/MCAsmInfo.h"12#include "llvm/MC/MCContext.h"13#include "llvm/MC/MCELFObjectWriter.h"14#include "llvm/MC/MCExpr.h"15#include "llvm/MC/MCFixup.h"16#include "llvm/MC/MCObjectWriter.h"17#include "llvm/MC/MCValue.h"18#include "llvm/Support/ErrorHandling.h"19#include <cassert>20#include <cstdint>2122using namespace llvm;2324namespace {2526class X86ELFObjectWriter : public MCELFObjectTargetWriter {27public:28X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine);29~X86ELFObjectWriter() override = default;3031protected:32unsigned getRelocType(MCContext &Ctx, const MCValue &Target,33const MCFixup &Fixup, bool IsPCRel) const override;34};3536} // end anonymous namespace3738X86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI,39uint16_t EMachine)40: MCELFObjectTargetWriter(IsELF64, OSABI, EMachine,41// Only i386 and IAMCU use Rel instead of RelA.42/*HasRelocationAddend*/43(EMachine != ELF::EM_386) &&44(EMachine != ELF::EM_IAMCU)) {}4546enum X86_64RelType { RT64_NONE, RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 };4748static X86_64RelType getType64(MCFixupKind Kind,49MCSymbolRefExpr::VariantKind &Modifier,50bool &IsPCRel) {51switch (unsigned(Kind)) {52default:53llvm_unreachable("Unimplemented");54case FK_NONE:55return RT64_NONE;56case X86::reloc_global_offset_table8:57Modifier = MCSymbolRefExpr::VK_GOT;58IsPCRel = true;59return RT64_64;60case FK_Data_8:61return RT64_64;62case X86::reloc_signed_4byte:63case X86::reloc_signed_4byte_relax:64if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel)65return RT64_32S;66return RT64_32;67case X86::reloc_global_offset_table:68Modifier = MCSymbolRefExpr::VK_GOT;69IsPCRel = true;70return RT64_32;71case FK_Data_4:72case FK_PCRel_4:73case X86::reloc_riprel_4byte:74case X86::reloc_riprel_4byte_relax:75case X86::reloc_riprel_4byte_relax_rex:76case X86::reloc_riprel_4byte_movq_load:77return RT64_32;78case X86::reloc_branch_4byte_pcrel:79Modifier = MCSymbolRefExpr::VK_PLT;80return RT64_32;81case FK_PCRel_2:82case FK_Data_2:83return RT64_16;84case FK_PCRel_1:85case FK_Data_1:86return RT64_8;87}88}8990static void checkIs32(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) {91if (Type != RT64_32)92Ctx.reportError(Loc,93"32 bit reloc applied to a field with a different size");94}9596static void checkIs64(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) {97if (Type != RT64_64)98Ctx.reportError(Loc,99"64 bit reloc applied to a field with a different size");100}101102static unsigned getRelocType64(MCContext &Ctx, SMLoc Loc,103MCSymbolRefExpr::VariantKind Modifier,104X86_64RelType Type, bool IsPCRel,105MCFixupKind Kind) {106switch (Modifier) {107default:108llvm_unreachable("Unimplemented");109case MCSymbolRefExpr::VK_None:110case MCSymbolRefExpr::VK_X86_ABS8:111switch (Type) {112case RT64_NONE:113if (Modifier == MCSymbolRefExpr::VK_None)114return ELF::R_X86_64_NONE;115llvm_unreachable("Unimplemented");116case RT64_64:117return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64;118case RT64_32:119return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32;120case RT64_32S:121return ELF::R_X86_64_32S;122case RT64_16:123return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16;124case RT64_8:125return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8;126}127llvm_unreachable("unexpected relocation type!");128case MCSymbolRefExpr::VK_GOT:129switch (Type) {130case RT64_64:131return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64;132case RT64_32:133return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32;134case RT64_32S:135case RT64_16:136case RT64_8:137case RT64_NONE:138llvm_unreachable("Unimplemented");139}140llvm_unreachable("unexpected relocation type!");141case MCSymbolRefExpr::VK_GOTOFF:142assert(!IsPCRel);143if (Type != RT64_64)144Ctx.reportError(Loc, "unsupported relocation type");145return ELF::R_X86_64_GOTOFF64;146case MCSymbolRefExpr::VK_TPOFF:147assert(!IsPCRel);148switch (Type) {149case RT64_64:150return ELF::R_X86_64_TPOFF64;151case RT64_32:152return ELF::R_X86_64_TPOFF32;153case RT64_32S:154case RT64_16:155case RT64_8:156case RT64_NONE:157llvm_unreachable("Unimplemented");158}159llvm_unreachable("unexpected relocation type!");160case MCSymbolRefExpr::VK_DTPOFF:161assert(!IsPCRel);162switch (Type) {163case RT64_64:164return ELF::R_X86_64_DTPOFF64;165case RT64_32:166return ELF::R_X86_64_DTPOFF32;167case RT64_32S:168case RT64_16:169case RT64_8:170case RT64_NONE:171llvm_unreachable("Unimplemented");172}173llvm_unreachable("unexpected relocation type!");174case MCSymbolRefExpr::VK_SIZE:175assert(!IsPCRel);176switch (Type) {177case RT64_64:178return ELF::R_X86_64_SIZE64;179case RT64_32:180return ELF::R_X86_64_SIZE32;181case RT64_32S:182case RT64_16:183case RT64_8:184case RT64_NONE:185llvm_unreachable("Unimplemented");186}187llvm_unreachable("unexpected relocation type!");188case MCSymbolRefExpr::VK_TLSCALL:189return ELF::R_X86_64_TLSDESC_CALL;190case MCSymbolRefExpr::VK_TLSDESC:191return ELF::R_X86_64_GOTPC32_TLSDESC;192case MCSymbolRefExpr::VK_TLSGD:193checkIs32(Ctx, Loc, Type);194return ELF::R_X86_64_TLSGD;195case MCSymbolRefExpr::VK_GOTTPOFF:196checkIs32(Ctx, Loc, Type);197return ELF::R_X86_64_GOTTPOFF;198case MCSymbolRefExpr::VK_TLSLD:199checkIs32(Ctx, Loc, Type);200return ELF::R_X86_64_TLSLD;201case MCSymbolRefExpr::VK_PLT:202checkIs32(Ctx, Loc, Type);203return ELF::R_X86_64_PLT32;204case MCSymbolRefExpr::VK_GOTPCREL:205checkIs32(Ctx, Loc, Type);206// Older versions of ld.bfd/ld.gold/lld207// do not support GOTPCRELX/REX_GOTPCRELX,208// and we want to keep back-compatibility.209if (!Ctx.getTargetOptions()->X86RelaxRelocations)210return ELF::R_X86_64_GOTPCREL;211switch (unsigned(Kind)) {212default:213return ELF::R_X86_64_GOTPCREL;214case X86::reloc_riprel_4byte_relax:215return ELF::R_X86_64_GOTPCRELX;216case X86::reloc_riprel_4byte_relax_rex:217case X86::reloc_riprel_4byte_movq_load:218return ELF::R_X86_64_REX_GOTPCRELX;219}220llvm_unreachable("unexpected relocation type!");221case MCSymbolRefExpr::VK_GOTPCREL_NORELAX:222checkIs32(Ctx, Loc, Type);223return ELF::R_X86_64_GOTPCREL;224case MCSymbolRefExpr::VK_X86_PLTOFF:225checkIs64(Ctx, Loc, Type);226return ELF::R_X86_64_PLTOFF64;227}228}229230enum X86_32RelType { RT32_NONE, RT32_32, RT32_16, RT32_8 };231232static unsigned getRelocType32(MCContext &Ctx, SMLoc Loc,233MCSymbolRefExpr::VariantKind Modifier,234X86_32RelType Type, bool IsPCRel,235MCFixupKind Kind) {236switch (Modifier) {237default:238llvm_unreachable("Unimplemented");239case MCSymbolRefExpr::VK_None:240case MCSymbolRefExpr::VK_X86_ABS8:241switch (Type) {242case RT32_NONE:243if (Modifier == MCSymbolRefExpr::VK_None)244return ELF::R_386_NONE;245llvm_unreachable("Unimplemented");246case RT32_32:247return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32;248case RT32_16:249return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16;250case RT32_8:251return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8;252}253llvm_unreachable("unexpected relocation type!");254case MCSymbolRefExpr::VK_GOT:255if (Type != RT32_32)256break;257if (IsPCRel)258return ELF::R_386_GOTPC;259// Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we260// want to maintain compatibility.261if (!Ctx.getTargetOptions()->X86RelaxRelocations)262return ELF::R_386_GOT32;263264return Kind == MCFixupKind(X86::reloc_signed_4byte_relax)265? ELF::R_386_GOT32X266: ELF::R_386_GOT32;267case MCSymbolRefExpr::VK_GOTOFF:268assert(!IsPCRel);269if (Type != RT32_32)270break;271return ELF::R_386_GOTOFF;272case MCSymbolRefExpr::VK_TLSCALL:273return ELF::R_386_TLS_DESC_CALL;274case MCSymbolRefExpr::VK_TLSDESC:275return ELF::R_386_TLS_GOTDESC;276case MCSymbolRefExpr::VK_TPOFF:277if (Type != RT32_32)278break;279assert(!IsPCRel);280return ELF::R_386_TLS_LE_32;281case MCSymbolRefExpr::VK_DTPOFF:282if (Type != RT32_32)283break;284assert(!IsPCRel);285return ELF::R_386_TLS_LDO_32;286case MCSymbolRefExpr::VK_TLSGD:287if (Type != RT32_32)288break;289assert(!IsPCRel);290return ELF::R_386_TLS_GD;291case MCSymbolRefExpr::VK_GOTTPOFF:292if (Type != RT32_32)293break;294assert(!IsPCRel);295return ELF::R_386_TLS_IE_32;296case MCSymbolRefExpr::VK_PLT:297if (Type != RT32_32)298break;299return ELF::R_386_PLT32;300case MCSymbolRefExpr::VK_INDNTPOFF:301if (Type != RT32_32)302break;303assert(!IsPCRel);304return ELF::R_386_TLS_IE;305case MCSymbolRefExpr::VK_NTPOFF:306if (Type != RT32_32)307break;308assert(!IsPCRel);309return ELF::R_386_TLS_LE;310case MCSymbolRefExpr::VK_GOTNTPOFF:311if (Type != RT32_32)312break;313assert(!IsPCRel);314return ELF::R_386_TLS_GOTIE;315case MCSymbolRefExpr::VK_TLSLDM:316if (Type != RT32_32)317break;318assert(!IsPCRel);319return ELF::R_386_TLS_LDM;320}321Ctx.reportError(Loc, "unsupported relocation type");322return ELF::R_386_NONE;323}324325unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,326const MCFixup &Fixup,327bool IsPCRel) const {328MCFixupKind Kind = Fixup.getKind();329if (Kind >= FirstLiteralRelocationKind)330return Kind - FirstLiteralRelocationKind;331MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();332X86_64RelType Type = getType64(Kind, Modifier, IsPCRel);333if (getEMachine() == ELF::EM_X86_64)334return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel, Kind);335336assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) &&337"Unsupported ELF machine type.");338339X86_32RelType RelType = RT32_NONE;340switch (Type) {341case RT64_NONE:342break;343case RT64_64:344Ctx.reportError(Fixup.getLoc(), "unsupported relocation type");345return ELF::R_386_NONE;346case RT64_32:347case RT64_32S:348RelType = RT32_32;349break;350case RT64_16:351RelType = RT32_16;352break;353case RT64_8:354RelType = RT32_8;355break;356}357return getRelocType32(Ctx, Fixup.getLoc(), Modifier, RelType, IsPCRel, Kind);358}359360std::unique_ptr<MCObjectTargetWriter>361llvm::createX86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine) {362return std::make_unique<X86ELFObjectWriter>(IsELF64, OSABI, EMachine);363}364365366