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