1251607Sdim//===-- SystemZMCObjectWriter.cpp - SystemZ ELF writer --------------------===// 2251607Sdim// 3251607Sdim// The LLVM Compiler Infrastructure 4251607Sdim// 5251607Sdim// This file is distributed under the University of Illinois Open Source 6251607Sdim// License. See LICENSE.TXT for details. 7251607Sdim// 8251607Sdim//===----------------------------------------------------------------------===// 9251607Sdim 10251607Sdim#include "MCTargetDesc/SystemZMCTargetDesc.h" 11251607Sdim#include "MCTargetDesc/SystemZMCFixups.h" 12251607Sdim#include "llvm/MC/MCELFObjectWriter.h" 13251607Sdim#include "llvm/MC/MCExpr.h" 14251607Sdim#include "llvm/MC/MCValue.h" 15251607Sdim 16251607Sdimusing namespace llvm; 17251607Sdim 18251607Sdimnamespace { 19251607Sdimclass SystemZObjectWriter : public MCELFObjectTargetWriter { 20251607Sdimpublic: 21251607Sdim SystemZObjectWriter(uint8_t OSABI); 22251607Sdim 23288943Sdim ~SystemZObjectWriter() override; 24251607Sdim 25251607Sdimprotected: 26251607Sdim // Override MCELFObjectTargetWriter. 27276479Sdim unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, 28276479Sdim bool IsPCRel) const override; 29251607Sdim}; 30276479Sdim} // end anonymous namespace 31251607Sdim 32251607SdimSystemZObjectWriter::SystemZObjectWriter(uint8_t OSABI) 33251607Sdim : MCELFObjectTargetWriter(/*Is64Bit=*/true, OSABI, ELF::EM_S390, 34251607Sdim /*HasRelocationAddend=*/ true) {} 35251607Sdim 36251607SdimSystemZObjectWriter::~SystemZObjectWriter() { 37251607Sdim} 38251607Sdim 39251607Sdim// Return the relocation type for an absolute value of MCFixupKind Kind. 40251607Sdimstatic unsigned getAbsoluteReloc(unsigned Kind) { 41251607Sdim switch (Kind) { 42251607Sdim case FK_Data_1: return ELF::R_390_8; 43251607Sdim case FK_Data_2: return ELF::R_390_16; 44251607Sdim case FK_Data_4: return ELF::R_390_32; 45251607Sdim case FK_Data_8: return ELF::R_390_64; 46251607Sdim } 47251607Sdim llvm_unreachable("Unsupported absolute address"); 48251607Sdim} 49251607Sdim 50251607Sdim// Return the relocation type for a PC-relative value of MCFixupKind Kind. 51251607Sdimstatic unsigned getPCRelReloc(unsigned Kind) { 52251607Sdim switch (Kind) { 53251607Sdim case FK_Data_2: return ELF::R_390_PC16; 54251607Sdim case FK_Data_4: return ELF::R_390_PC32; 55251607Sdim case FK_Data_8: return ELF::R_390_PC64; 56251607Sdim case SystemZ::FK_390_PC16DBL: return ELF::R_390_PC16DBL; 57251607Sdim case SystemZ::FK_390_PC32DBL: return ELF::R_390_PC32DBL; 58251607Sdim } 59251607Sdim llvm_unreachable("Unsupported PC-relative address"); 60251607Sdim} 61251607Sdim 62251607Sdim// Return the R_390_TLS_LE* relocation type for MCFixupKind Kind. 63251607Sdimstatic unsigned getTLSLEReloc(unsigned Kind) { 64251607Sdim switch (Kind) { 65251607Sdim case FK_Data_4: return ELF::R_390_TLS_LE32; 66251607Sdim case FK_Data_8: return ELF::R_390_TLS_LE64; 67251607Sdim } 68251607Sdim llvm_unreachable("Unsupported absolute address"); 69251607Sdim} 70251607Sdim 71288943Sdim// Return the R_390_TLS_LDO* relocation type for MCFixupKind Kind. 72288943Sdimstatic unsigned getTLSLDOReloc(unsigned Kind) { 73288943Sdim switch (Kind) { 74288943Sdim case FK_Data_4: return ELF::R_390_TLS_LDO32; 75288943Sdim case FK_Data_8: return ELF::R_390_TLS_LDO64; 76288943Sdim } 77288943Sdim llvm_unreachable("Unsupported absolute address"); 78288943Sdim} 79288943Sdim 80288943Sdim// Return the R_390_TLS_LDM* relocation type for MCFixupKind Kind. 81288943Sdimstatic unsigned getTLSLDMReloc(unsigned Kind) { 82288943Sdim switch (Kind) { 83288943Sdim case FK_Data_4: return ELF::R_390_TLS_LDM32; 84288943Sdim case FK_Data_8: return ELF::R_390_TLS_LDM64; 85288943Sdim case SystemZ::FK_390_TLS_CALL: return ELF::R_390_TLS_LDCALL; 86288943Sdim } 87288943Sdim llvm_unreachable("Unsupported absolute address"); 88288943Sdim} 89288943Sdim 90288943Sdim// Return the R_390_TLS_GD* relocation type for MCFixupKind Kind. 91288943Sdimstatic unsigned getTLSGDReloc(unsigned Kind) { 92288943Sdim switch (Kind) { 93288943Sdim case FK_Data_4: return ELF::R_390_TLS_GD32; 94288943Sdim case FK_Data_8: return ELF::R_390_TLS_GD64; 95288943Sdim case SystemZ::FK_390_TLS_CALL: return ELF::R_390_TLS_GDCALL; 96288943Sdim } 97288943Sdim llvm_unreachable("Unsupported absolute address"); 98288943Sdim} 99288943Sdim 100251607Sdim// Return the PLT relocation counterpart of MCFixupKind Kind. 101251607Sdimstatic unsigned getPLTReloc(unsigned Kind) { 102251607Sdim switch (Kind) { 103251607Sdim case SystemZ::FK_390_PC16DBL: return ELF::R_390_PLT16DBL; 104251607Sdim case SystemZ::FK_390_PC32DBL: return ELF::R_390_PLT32DBL; 105251607Sdim } 106251607Sdim llvm_unreachable("Unsupported absolute address"); 107251607Sdim} 108251607Sdim 109251607Sdimunsigned SystemZObjectWriter::GetRelocType(const MCValue &Target, 110251607Sdim const MCFixup &Fixup, 111276479Sdim bool IsPCRel) const { 112276479Sdim MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); 113251607Sdim unsigned Kind = Fixup.getKind(); 114251607Sdim switch (Modifier) { 115251607Sdim case MCSymbolRefExpr::VK_None: 116251607Sdim if (IsPCRel) 117251607Sdim return getPCRelReloc(Kind); 118251607Sdim return getAbsoluteReloc(Kind); 119251607Sdim 120251607Sdim case MCSymbolRefExpr::VK_NTPOFF: 121251607Sdim assert(!IsPCRel && "NTPOFF shouldn't be PC-relative"); 122251607Sdim return getTLSLEReloc(Kind); 123251607Sdim 124288943Sdim case MCSymbolRefExpr::VK_INDNTPOFF: 125288943Sdim if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) 126288943Sdim return ELF::R_390_TLS_IEENT; 127288943Sdim llvm_unreachable("Only PC-relative INDNTPOFF accesses are supported for now"); 128288943Sdim 129288943Sdim case MCSymbolRefExpr::VK_DTPOFF: 130288943Sdim assert(!IsPCRel && "DTPOFF shouldn't be PC-relative"); 131288943Sdim return getTLSLDOReloc(Kind); 132288943Sdim 133288943Sdim case MCSymbolRefExpr::VK_TLSLDM: 134288943Sdim assert(!IsPCRel && "TLSLDM shouldn't be PC-relative"); 135288943Sdim return getTLSLDMReloc(Kind); 136288943Sdim 137288943Sdim case MCSymbolRefExpr::VK_TLSGD: 138288943Sdim assert(!IsPCRel && "TLSGD shouldn't be PC-relative"); 139288943Sdim return getTLSGDReloc(Kind); 140288943Sdim 141251607Sdim case MCSymbolRefExpr::VK_GOT: 142251607Sdim if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) 143251607Sdim return ELF::R_390_GOTENT; 144251607Sdim llvm_unreachable("Only PC-relative GOT accesses are supported for now"); 145251607Sdim 146251607Sdim case MCSymbolRefExpr::VK_PLT: 147251607Sdim assert(IsPCRel && "@PLT shouldt be PC-relative"); 148251607Sdim return getPLTReloc(Kind); 149251607Sdim 150251607Sdim default: 151251607Sdim llvm_unreachable("Modifier not supported"); 152251607Sdim } 153251607Sdim} 154251607Sdim 155288943SdimMCObjectWriter *llvm::createSystemZObjectWriter(raw_pwrite_stream &OS, 156251607Sdim uint8_t OSABI) { 157251607Sdim MCELFObjectTargetWriter *MOTW = new SystemZObjectWriter(OSABI); 158251607Sdim return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false); 159251607Sdim} 160