//===-- SystemZMCObjectWriter.cpp - SystemZ ELF writer --------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "MCTargetDesc/SystemZMCTargetDesc.h" #include "MCTargetDesc/SystemZMCFixups.h" #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCValue.h" using namespace llvm; namespace { class SystemZObjectWriter : public MCELFObjectTargetWriter { public: SystemZObjectWriter(uint8_t OSABI); virtual ~SystemZObjectWriter(); protected: // Override MCELFObjectTargetWriter. virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel, bool IsRelocWithSymbol, int64_t Addend) const LLVM_OVERRIDE; virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, const MCValue &Target, const MCFragment &F, const MCFixup &Fixup, bool IsPCRel) const LLVM_OVERRIDE; }; } // end anonymouse namespace SystemZObjectWriter::SystemZObjectWriter(uint8_t OSABI) : MCELFObjectTargetWriter(/*Is64Bit=*/true, OSABI, ELF::EM_S390, /*HasRelocationAddend=*/ true) {} SystemZObjectWriter::~SystemZObjectWriter() { } // Return the relocation type for an absolute value of MCFixupKind Kind. static unsigned getAbsoluteReloc(unsigned Kind) { switch (Kind) { case FK_Data_1: return ELF::R_390_8; case FK_Data_2: return ELF::R_390_16; case FK_Data_4: return ELF::R_390_32; case FK_Data_8: return ELF::R_390_64; } llvm_unreachable("Unsupported absolute address"); } // Return the relocation type for a PC-relative value of MCFixupKind Kind. static unsigned getPCRelReloc(unsigned Kind) { switch (Kind) { case FK_Data_2: return ELF::R_390_PC16; case FK_Data_4: return ELF::R_390_PC32; case FK_Data_8: return ELF::R_390_PC64; case SystemZ::FK_390_PC16DBL: return ELF::R_390_PC16DBL; case SystemZ::FK_390_PC32DBL: return ELF::R_390_PC32DBL; case SystemZ::FK_390_PLT16DBL: return ELF::R_390_PLT16DBL; case SystemZ::FK_390_PLT32DBL: return ELF::R_390_PLT32DBL; } llvm_unreachable("Unsupported PC-relative address"); } // Return the R_390_TLS_LE* relocation type for MCFixupKind Kind. static unsigned getTLSLEReloc(unsigned Kind) { switch (Kind) { case FK_Data_4: return ELF::R_390_TLS_LE32; case FK_Data_8: return ELF::R_390_TLS_LE64; } llvm_unreachable("Unsupported absolute address"); } // Return the PLT relocation counterpart of MCFixupKind Kind. static unsigned getPLTReloc(unsigned Kind) { switch (Kind) { case SystemZ::FK_390_PC16DBL: return ELF::R_390_PLT16DBL; case SystemZ::FK_390_PC32DBL: return ELF::R_390_PLT32DBL; } llvm_unreachable("Unsupported absolute address"); } unsigned SystemZObjectWriter::GetRelocType(const MCValue &Target, const MCFixup &Fixup, bool IsPCRel, bool IsRelocWithSymbol, int64_t Addend) const { MCSymbolRefExpr::VariantKind Modifier = (Target.isAbsolute() ? MCSymbolRefExpr::VK_None : Target.getSymA()->getKind()); unsigned Kind = Fixup.getKind(); switch (Modifier) { case MCSymbolRefExpr::VK_None: if (IsPCRel) return getPCRelReloc(Kind); return getAbsoluteReloc(Kind); case MCSymbolRefExpr::VK_NTPOFF: assert(!IsPCRel && "NTPOFF shouldn't be PC-relative"); return getTLSLEReloc(Kind); case MCSymbolRefExpr::VK_GOT: if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) return ELF::R_390_GOTENT; llvm_unreachable("Only PC-relative GOT accesses are supported for now"); case MCSymbolRefExpr::VK_PLT: assert(IsPCRel && "@PLT shouldt be PC-relative"); return getPLTReloc(Kind); default: llvm_unreachable("Modifier not supported"); } } const MCSymbol *SystemZObjectWriter::ExplicitRelSym(const MCAssembler &Asm, const MCValue &Target, const MCFragment &F, const MCFixup &Fixup, bool IsPCRel) const { // The addend in a PC-relative R_390_* relocation is always applied to // the PC-relative part of the address. If some kind of indirection // is applied to the symbol first, we can't use an addend there too. if (!Target.isAbsolute() && Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None && IsPCRel) return &Target.getSymA()->getSymbol().AliasedSymbol(); return NULL; } MCObjectWriter *llvm::createSystemZObjectWriter(raw_ostream &OS, uint8_t OSABI) { MCELFObjectTargetWriter *MOTW = new SystemZObjectWriter(OSABI); return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false); }