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 21 using namespace llvm; 22 23 namespace { 24 25 class SystemZObjectWriter : public MCELFObjectTargetWriter { 26 public: 27 SystemZObjectWriter(uint8_t OSABI); 28 ~SystemZObjectWriter() override = default; 29 30 protected: 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 38 SystemZObjectWriter::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. 43 static 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. 54 static 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. 68 static 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. 77 static 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. 86 static 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. 96 static 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. 106 static 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 116 unsigned SystemZObjectWriter::getRelocType(MCContext &Ctx, 117 const MCValue &Target, 118 const MCFixup &Fixup, 119 bool IsPCRel) const { 120 unsigned Kind = Fixup.getKind(); 121 if (Kind >= FirstLiteralRelocationKind) 122 return Kind - FirstLiteralRelocationKind; 123 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); 124 switch (Modifier) { 125 case MCSymbolRefExpr::VK_None: 126 if (IsPCRel) 127 return getPCRelReloc(Kind); 128 return getAbsoluteReloc(Kind); 129 130 case MCSymbolRefExpr::VK_NTPOFF: 131 assert(!IsPCRel && "NTPOFF shouldn't be PC-relative"); 132 return getTLSLEReloc(Kind); 133 134 case MCSymbolRefExpr::VK_INDNTPOFF: 135 if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) 136 return ELF::R_390_TLS_IEENT; 137 llvm_unreachable("Only PC-relative INDNTPOFF accesses are supported for now"); 138 139 case MCSymbolRefExpr::VK_DTPOFF: 140 assert(!IsPCRel && "DTPOFF shouldn't be PC-relative"); 141 return getTLSLDOReloc(Kind); 142 143 case MCSymbolRefExpr::VK_TLSLDM: 144 assert(!IsPCRel && "TLSLDM shouldn't be PC-relative"); 145 return getTLSLDMReloc(Kind); 146 147 case MCSymbolRefExpr::VK_TLSGD: 148 assert(!IsPCRel && "TLSGD shouldn't be PC-relative"); 149 return getTLSGDReloc(Kind); 150 151 case MCSymbolRefExpr::VK_GOT: 152 if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) 153 return ELF::R_390_GOTENT; 154 llvm_unreachable("Only PC-relative GOT accesses are supported for now"); 155 156 case MCSymbolRefExpr::VK_PLT: 157 assert(IsPCRel && "@PLT shouldt be PC-relative"); 158 return getPLTReloc(Kind); 159 160 default: 161 llvm_unreachable("Modifier not supported"); 162 } 163 } 164 165 std::unique_ptr<MCObjectTargetWriter> 166 llvm::createSystemZObjectWriter(uint8_t OSABI) { 167 return std::make_unique<SystemZObjectWriter>(OSABI); 168 } 169