1//===-- SystemZMCObjectWriter.cpp - SystemZ 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-exception 6// 7//===----------------------------------------------------------------------===// 8 9#include "MCTargetDesc/SystemZMCFixups.h" 10#include "MCTargetDesc/SystemZMCTargetDesc.h" 11#include "llvm/BinaryFormat/ELF.h" 12#include "llvm/MC/MCELFObjectWriter.h" 13#include "llvm/MC/MCExpr.h" 14#include "llvm/MC/MCFixup.h" 15#include "llvm/MC/MCObjectWriter.h" 16#include "llvm/MC/MCValue.h" 17#include "llvm/Support/ErrorHandling.h" 18#include <cassert> 19#include <cstdint> 20 21using namespace llvm; 22 23namespace { 24 25class SystemZObjectWriter : public MCELFObjectTargetWriter { 26public: 27 SystemZObjectWriter(uint8_t OSABI); 28 ~SystemZObjectWriter() override = default; 29 30protected: 31 // Override MCELFObjectTargetWriter. 32 unsigned getRelocType(MCContext &Ctx, const MCValue &Target, 33 const MCFixup &Fixup, bool IsPCRel) const override; 34}; 35 36} // end anonymous namespace 37 38SystemZObjectWriter::SystemZObjectWriter(uint8_t OSABI) 39 : MCELFObjectTargetWriter(/*Is64Bit_=*/true, OSABI, ELF::EM_S390, 40 /*HasRelocationAddend_=*/ true) {} 41 42// Return the relocation type for an absolute value of MCFixupKind Kind. 43static unsigned getAbsoluteReloc(unsigned Kind) { 44 switch (Kind) { 45 case FK_Data_1: return ELF::R_390_8; 46 case FK_Data_2: return ELF::R_390_16; 47 case FK_Data_4: return ELF::R_390_32; 48 case FK_Data_8: return ELF::R_390_64; 49 } 50 llvm_unreachable("Unsupported absolute address"); 51} 52 53// Return the relocation type for a PC-relative value of MCFixupKind Kind. 54static unsigned getPCRelReloc(unsigned Kind) { 55 switch (Kind) { 56 case FK_Data_2: return ELF::R_390_PC16; 57 case FK_Data_4: return ELF::R_390_PC32; 58 case FK_Data_8: return ELF::R_390_PC64; 59 case SystemZ::FK_390_PC12DBL: return ELF::R_390_PC12DBL; 60 case SystemZ::FK_390_PC16DBL: return ELF::R_390_PC16DBL; 61 case SystemZ::FK_390_PC24DBL: return ELF::R_390_PC24DBL; 62 case SystemZ::FK_390_PC32DBL: return ELF::R_390_PC32DBL; 63 } 64 llvm_unreachable("Unsupported PC-relative address"); 65} 66 67// Return the R_390_TLS_LE* relocation type for MCFixupKind Kind. 68static unsigned getTLSLEReloc(unsigned Kind) { 69 switch (Kind) { 70 case FK_Data_4: return ELF::R_390_TLS_LE32; 71 case FK_Data_8: return ELF::R_390_TLS_LE64; 72 } 73 llvm_unreachable("Unsupported absolute address"); 74} 75 76// Return the R_390_TLS_LDO* relocation type for MCFixupKind Kind. 77static unsigned getTLSLDOReloc(unsigned Kind) { 78 switch (Kind) { 79 case FK_Data_4: return ELF::R_390_TLS_LDO32; 80 case FK_Data_8: return ELF::R_390_TLS_LDO64; 81 } 82 llvm_unreachable("Unsupported absolute address"); 83} 84 85// Return the R_390_TLS_LDM* relocation type for MCFixupKind Kind. 86static unsigned getTLSLDMReloc(unsigned Kind) { 87 switch (Kind) { 88 case FK_Data_4: return ELF::R_390_TLS_LDM32; 89 case FK_Data_8: return ELF::R_390_TLS_LDM64; 90 case SystemZ::FK_390_TLS_CALL: return ELF::R_390_TLS_LDCALL; 91 } 92 llvm_unreachable("Unsupported absolute address"); 93} 94 95// Return the R_390_TLS_GD* relocation type for MCFixupKind Kind. 96static unsigned getTLSGDReloc(unsigned Kind) { 97 switch (Kind) { 98 case FK_Data_4: return ELF::R_390_TLS_GD32; 99 case FK_Data_8: return ELF::R_390_TLS_GD64; 100 case SystemZ::FK_390_TLS_CALL: return ELF::R_390_TLS_GDCALL; 101 } 102 llvm_unreachable("Unsupported absolute address"); 103} 104 105// Return the PLT relocation counterpart of MCFixupKind Kind. 106static unsigned getPLTReloc(unsigned Kind) { 107 switch (Kind) { 108 case SystemZ::FK_390_PC12DBL: return ELF::R_390_PLT12DBL; 109 case SystemZ::FK_390_PC16DBL: return ELF::R_390_PLT16DBL; 110 case SystemZ::FK_390_PC24DBL: return ELF::R_390_PLT24DBL; 111 case SystemZ::FK_390_PC32DBL: return ELF::R_390_PLT32DBL; 112 } 113 llvm_unreachable("Unsupported absolute address"); 114} 115 116unsigned SystemZObjectWriter::getRelocType(MCContext &Ctx, 117 const MCValue &Target, 118 const MCFixup &Fixup, 119 bool IsPCRel) const { 120 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); 121 unsigned Kind = Fixup.getKind(); 122 switch (Modifier) { 123 case MCSymbolRefExpr::VK_None: 124 if (IsPCRel) 125 return getPCRelReloc(Kind); 126 return getAbsoluteReloc(Kind); 127 128 case MCSymbolRefExpr::VK_NTPOFF: 129 assert(!IsPCRel && "NTPOFF shouldn't be PC-relative"); 130 return getTLSLEReloc(Kind); 131 132 case MCSymbolRefExpr::VK_INDNTPOFF: 133 if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) 134 return ELF::R_390_TLS_IEENT; 135 llvm_unreachable("Only PC-relative INDNTPOFF accesses are supported for now"); 136 137 case MCSymbolRefExpr::VK_DTPOFF: 138 assert(!IsPCRel && "DTPOFF shouldn't be PC-relative"); 139 return getTLSLDOReloc(Kind); 140 141 case MCSymbolRefExpr::VK_TLSLDM: 142 assert(!IsPCRel && "TLSLDM shouldn't be PC-relative"); 143 return getTLSLDMReloc(Kind); 144 145 case MCSymbolRefExpr::VK_TLSGD: 146 assert(!IsPCRel && "TLSGD shouldn't be PC-relative"); 147 return getTLSGDReloc(Kind); 148 149 case MCSymbolRefExpr::VK_GOT: 150 if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) 151 return ELF::R_390_GOTENT; 152 llvm_unreachable("Only PC-relative GOT accesses are supported for now"); 153 154 case MCSymbolRefExpr::VK_PLT: 155 assert(IsPCRel && "@PLT shouldt be PC-relative"); 156 return getPLTReloc(Kind); 157 158 default: 159 llvm_unreachable("Modifier not supported"); 160 } 161} 162 163std::unique_ptr<MCObjectTargetWriter> 164llvm::createSystemZObjectWriter(uint8_t OSABI) { 165 return std::make_unique<SystemZObjectWriter>(OSABI); 166} 167