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