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 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 163 std::unique_ptr<MCObjectTargetWriter> 164 llvm::createSystemZObjectWriter(uint8_t OSABI) { 165 return std::make_unique<SystemZObjectWriter>(OSABI); 166 } 167