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 case SystemZ::FK_390_12: return ELF::R_390_12; 50 case SystemZ::FK_390_20: return ELF::R_390_20; 51 } 52 llvm_unreachable("Unsupported absolute address"); 53 } 54 55 // Return the relocation type for a PC-relative value of MCFixupKind Kind. 56 static unsigned getPCRelReloc(unsigned Kind) { 57 switch (Kind) { 58 case FK_Data_2: return ELF::R_390_PC16; 59 case FK_Data_4: return ELF::R_390_PC32; 60 case FK_Data_8: return ELF::R_390_PC64; 61 case SystemZ::FK_390_PC12DBL: return ELF::R_390_PC12DBL; 62 case SystemZ::FK_390_PC16DBL: return ELF::R_390_PC16DBL; 63 case SystemZ::FK_390_PC24DBL: return ELF::R_390_PC24DBL; 64 case SystemZ::FK_390_PC32DBL: return ELF::R_390_PC32DBL; 65 } 66 llvm_unreachable("Unsupported PC-relative address"); 67 } 68 69 // Return the R_390_TLS_LE* relocation type for MCFixupKind Kind. 70 static unsigned getTLSLEReloc(unsigned Kind) { 71 switch (Kind) { 72 case FK_Data_4: return ELF::R_390_TLS_LE32; 73 case FK_Data_8: return ELF::R_390_TLS_LE64; 74 } 75 llvm_unreachable("Unsupported absolute address"); 76 } 77 78 // Return the R_390_TLS_LDO* relocation type for MCFixupKind Kind. 79 static unsigned getTLSLDOReloc(unsigned Kind) { 80 switch (Kind) { 81 case FK_Data_4: return ELF::R_390_TLS_LDO32; 82 case FK_Data_8: return ELF::R_390_TLS_LDO64; 83 } 84 llvm_unreachable("Unsupported absolute address"); 85 } 86 87 // Return the R_390_TLS_LDM* relocation type for MCFixupKind Kind. 88 static unsigned getTLSLDMReloc(unsigned Kind) { 89 switch (Kind) { 90 case FK_Data_4: return ELF::R_390_TLS_LDM32; 91 case FK_Data_8: return ELF::R_390_TLS_LDM64; 92 case SystemZ::FK_390_TLS_CALL: return ELF::R_390_TLS_LDCALL; 93 } 94 llvm_unreachable("Unsupported absolute address"); 95 } 96 97 // Return the R_390_TLS_GD* relocation type for MCFixupKind Kind. 98 static unsigned getTLSGDReloc(unsigned Kind) { 99 switch (Kind) { 100 case FK_Data_4: return ELF::R_390_TLS_GD32; 101 case FK_Data_8: return ELF::R_390_TLS_GD64; 102 case SystemZ::FK_390_TLS_CALL: return ELF::R_390_TLS_GDCALL; 103 } 104 llvm_unreachable("Unsupported absolute address"); 105 } 106 107 // Return the PLT relocation counterpart of MCFixupKind Kind. 108 static unsigned getPLTReloc(unsigned Kind) { 109 switch (Kind) { 110 case SystemZ::FK_390_PC12DBL: return ELF::R_390_PLT12DBL; 111 case SystemZ::FK_390_PC16DBL: return ELF::R_390_PLT16DBL; 112 case SystemZ::FK_390_PC24DBL: return ELF::R_390_PLT24DBL; 113 case SystemZ::FK_390_PC32DBL: return ELF::R_390_PLT32DBL; 114 } 115 llvm_unreachable("Unsupported absolute address"); 116 } 117 118 unsigned SystemZObjectWriter::getRelocType(MCContext &Ctx, 119 const MCValue &Target, 120 const MCFixup &Fixup, 121 bool IsPCRel) const { 122 unsigned Kind = Fixup.getKind(); 123 if (Kind >= FirstLiteralRelocationKind) 124 return Kind - FirstLiteralRelocationKind; 125 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); 126 switch (Modifier) { 127 case MCSymbolRefExpr::VK_None: 128 if (IsPCRel) 129 return getPCRelReloc(Kind); 130 return getAbsoluteReloc(Kind); 131 132 case MCSymbolRefExpr::VK_NTPOFF: 133 assert(!IsPCRel && "NTPOFF shouldn't be PC-relative"); 134 return getTLSLEReloc(Kind); 135 136 case MCSymbolRefExpr::VK_INDNTPOFF: 137 if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) 138 return ELF::R_390_TLS_IEENT; 139 llvm_unreachable("Only PC-relative INDNTPOFF accesses are supported for now"); 140 141 case MCSymbolRefExpr::VK_DTPOFF: 142 assert(!IsPCRel && "DTPOFF shouldn't be PC-relative"); 143 return getTLSLDOReloc(Kind); 144 145 case MCSymbolRefExpr::VK_TLSLDM: 146 assert(!IsPCRel && "TLSLDM shouldn't be PC-relative"); 147 return getTLSLDMReloc(Kind); 148 149 case MCSymbolRefExpr::VK_TLSGD: 150 assert(!IsPCRel && "TLSGD shouldn't be PC-relative"); 151 return getTLSGDReloc(Kind); 152 153 case MCSymbolRefExpr::VK_GOT: 154 if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) 155 return ELF::R_390_GOTENT; 156 llvm_unreachable("Only PC-relative GOT accesses are supported for now"); 157 158 case MCSymbolRefExpr::VK_PLT: 159 assert(IsPCRel && "@PLT shouldt be PC-relative"); 160 return getPLTReloc(Kind); 161 162 default: 163 llvm_unreachable("Modifier not supported"); 164 } 165 } 166 167 std::unique_ptr<MCObjectTargetWriter> 168 llvm::createSystemZObjectWriter(uint8_t OSABI) { 169 return std::make_unique<SystemZObjectWriter>(OSABI); 170 } 171