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 void sortRelocs(const MCAssembler &Asm, 30 std::vector<ELFRelocationEntry> &Relocs) override; 31 }; 32 } // end anonymous namespace 33 34 SystemZObjectWriter::SystemZObjectWriter(uint8_t OSABI) 35 : MCELFObjectTargetWriter(/*Is64Bit=*/true, OSABI, ELF::EM_S390, 36 /*HasRelocationAddend=*/ true) {} 37 38 SystemZObjectWriter::~SystemZObjectWriter() { 39 } 40 41 // Return the relocation type for an absolute value of MCFixupKind Kind. 42 static unsigned getAbsoluteReloc(unsigned Kind) { 43 switch (Kind) { 44 case FK_Data_1: return ELF::R_390_8; 45 case FK_Data_2: return ELF::R_390_16; 46 case FK_Data_4: return ELF::R_390_32; 47 case FK_Data_8: return ELF::R_390_64; 48 } 49 llvm_unreachable("Unsupported absolute address"); 50 } 51 52 // Return the relocation type for a PC-relative value of MCFixupKind Kind. 53 static unsigned getPCRelReloc(unsigned Kind) { 54 switch (Kind) { 55 case FK_Data_2: return ELF::R_390_PC16; 56 case FK_Data_4: return ELF::R_390_PC32; 57 case FK_Data_8: return ELF::R_390_PC64; 58 case SystemZ::FK_390_PC16DBL: return ELF::R_390_PC16DBL; 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_PC16DBL: return ELF::R_390_PLT16DBL; 106 case SystemZ::FK_390_PC32DBL: return ELF::R_390_PLT32DBL; 107 } 108 llvm_unreachable("Unsupported absolute address"); 109 } 110 111 unsigned SystemZObjectWriter::GetRelocType(const MCValue &Target, 112 const MCFixup &Fixup, 113 bool IsPCRel) const { 114 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); 115 unsigned Kind = Fixup.getKind(); 116 switch (Modifier) { 117 case MCSymbolRefExpr::VK_None: 118 if (IsPCRel) 119 return getPCRelReloc(Kind); 120 return getAbsoluteReloc(Kind); 121 122 case MCSymbolRefExpr::VK_NTPOFF: 123 assert(!IsPCRel && "NTPOFF shouldn't be PC-relative"); 124 return getTLSLEReloc(Kind); 125 126 case MCSymbolRefExpr::VK_INDNTPOFF: 127 if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) 128 return ELF::R_390_TLS_IEENT; 129 llvm_unreachable("Only PC-relative INDNTPOFF accesses are supported for now"); 130 131 case MCSymbolRefExpr::VK_DTPOFF: 132 assert(!IsPCRel && "DTPOFF shouldn't be PC-relative"); 133 return getTLSLDOReloc(Kind); 134 135 case MCSymbolRefExpr::VK_TLSLDM: 136 assert(!IsPCRel && "TLSLDM shouldn't be PC-relative"); 137 return getTLSLDMReloc(Kind); 138 139 case MCSymbolRefExpr::VK_TLSGD: 140 assert(!IsPCRel && "TLSGD shouldn't be PC-relative"); 141 return getTLSGDReloc(Kind); 142 143 case MCSymbolRefExpr::VK_GOT: 144 if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) 145 return ELF::R_390_GOTENT; 146 llvm_unreachable("Only PC-relative GOT accesses are supported for now"); 147 148 case MCSymbolRefExpr::VK_PLT: 149 assert(IsPCRel && "@PLT shouldt be PC-relative"); 150 return getPLTReloc(Kind); 151 152 default: 153 llvm_unreachable("Modifier not supported"); 154 } 155 } 156 157 void SystemZObjectWriter::sortRelocs(const MCAssembler &Asm, 158 std::vector<ELFRelocationEntry> &Relocs) { 159 // The default function sorts entries by Offset in descending order. 160 MCELFObjectTargetWriter::sortRelocs(Asm, Relocs); 161 162 // This is OK for SystemZ, except for R_390_TLS_GDCALL/LDCALL relocs. 163 // There is typically another reloc, a R_390_PLT32DBL, on the same 164 // instruction. This other reloc must come *before* the GDCALL reloc, 165 // or else the TLS linker optimization may generate incorrect code. 166 for (unsigned i = 0, e = Relocs.size(); i + 1 < e; ++i) { 167 if ((Relocs[i + 1].Type == ELF::R_390_TLS_GDCALL || 168 Relocs[i + 1].Type == ELF::R_390_TLS_LDCALL) && 169 Relocs[i].Offset == Relocs[i + 1].Offset + 2) 170 std::swap(Relocs[i], Relocs[i + 1]); 171 } 172 } 173 174 MCObjectWriter *llvm::createSystemZObjectWriter(raw_pwrite_stream &OS, 175 uint8_t OSABI) { 176 MCELFObjectTargetWriter *MOTW = new SystemZObjectWriter(OSABI); 177 return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false); 178 } 179