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