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(const MCValue &Target, const MCFixup &Fixup, 28 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(const MCValue &Target, 110 const MCFixup &Fixup, 111 bool IsPCRel) const { 112 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); 113 unsigned Kind = Fixup.getKind(); 114 switch (Modifier) { 115 case MCSymbolRefExpr::VK_None: 116 if (IsPCRel) 117 return getPCRelReloc(Kind); 118 return getAbsoluteReloc(Kind); 119 120 case MCSymbolRefExpr::VK_NTPOFF: 121 assert(!IsPCRel && "NTPOFF shouldn't be PC-relative"); 122 return getTLSLEReloc(Kind); 123 124 case MCSymbolRefExpr::VK_INDNTPOFF: 125 if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) 126 return ELF::R_390_TLS_IEENT; 127 llvm_unreachable("Only PC-relative INDNTPOFF accesses are supported for now"); 128 129 case MCSymbolRefExpr::VK_DTPOFF: 130 assert(!IsPCRel && "DTPOFF shouldn't be PC-relative"); 131 return getTLSLDOReloc(Kind); 132 133 case MCSymbolRefExpr::VK_TLSLDM: 134 assert(!IsPCRel && "TLSLDM shouldn't be PC-relative"); 135 return getTLSLDMReloc(Kind); 136 137 case MCSymbolRefExpr::VK_TLSGD: 138 assert(!IsPCRel && "TLSGD shouldn't be PC-relative"); 139 return getTLSGDReloc(Kind); 140 141 case MCSymbolRefExpr::VK_GOT: 142 if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) 143 return ELF::R_390_GOTENT; 144 llvm_unreachable("Only PC-relative GOT accesses are supported for now"); 145 146 case MCSymbolRefExpr::VK_PLT: 147 assert(IsPCRel && "@PLT shouldt be PC-relative"); 148 return getPLTReloc(Kind); 149 150 default: 151 llvm_unreachable("Modifier not supported"); 152 } 153 } 154 155 MCObjectWriter *llvm::createSystemZObjectWriter(raw_pwrite_stream &OS, 156 uint8_t OSABI) { 157 MCELFObjectTargetWriter *MOTW = new SystemZObjectWriter(OSABI); 158 return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false); 159 } 160