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