//===-- SystemZELFObjectWriter.cpp - SystemZ ELF writer -------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "MCTargetDesc/SystemZMCAsmInfo.h" #include "MCTargetDesc/SystemZMCFixups.h" #include "MCTargetDesc/SystemZMCTargetDesc.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/ErrorHandling.h" #include #include #include using namespace llvm; namespace { class SystemZELFObjectWriter : public MCELFObjectTargetWriter { public: SystemZELFObjectWriter(uint8_t OSABI); ~SystemZELFObjectWriter() override = default; protected: // Override MCELFObjectTargetWriter. unsigned getRelocType(const MCFixup &, const MCValue &, bool IsPCRel) const override; bool needsRelocateWithSymbol(const MCValue &, unsigned Type) const override; unsigned getAbsoluteReloc(SMLoc Loc, unsigned Kind) const; unsigned getPCRelReloc(SMLoc Loc, unsigned Kind) const; }; } // end anonymous namespace SystemZELFObjectWriter::SystemZELFObjectWriter(uint8_t OSABI) : MCELFObjectTargetWriter(/*Is64Bit_=*/true, OSABI, ELF::EM_S390, /*HasRelocationAddend_=*/true) {} // Return the relocation type for an absolute value of MCFixupKind Kind. unsigned SystemZELFObjectWriter::getAbsoluteReloc(SMLoc Loc, unsigned Kind) const { switch (Kind) { case FK_Data_1: case SystemZ::FK_390_U8Imm: case SystemZ::FK_390_S8Imm: return ELF::R_390_8; case SystemZ::FK_390_U12Imm: return ELF::R_390_12; case FK_Data_2: case SystemZ::FK_390_U16Imm: case SystemZ::FK_390_S16Imm: return ELF::R_390_16; case SystemZ::FK_390_S20Imm: return ELF::R_390_20; case FK_Data_4: case SystemZ::FK_390_U32Imm: case SystemZ::FK_390_S32Imm: return ELF::R_390_32; case FK_Data_8: return ELF::R_390_64; } reportError(Loc, "Unsupported absolute address"); return 0; } // Return the relocation type for a PC-relative value of MCFixupKind Kind. unsigned SystemZELFObjectWriter::getPCRelReloc(SMLoc Loc, unsigned Kind) const { switch (Kind) { case FK_Data_2: case SystemZ::FK_390_U16Imm: case SystemZ::FK_390_S16Imm: return ELF::R_390_PC16; case FK_Data_4: case SystemZ::FK_390_U32Imm: case SystemZ::FK_390_S32Imm: return ELF::R_390_PC32; case FK_Data_8: return ELF::R_390_PC64; case SystemZ::FK_390_PC12DBL: return ELF::R_390_PC12DBL; case SystemZ::FK_390_PC16DBL: return ELF::R_390_PC16DBL; case SystemZ::FK_390_PC24DBL: return ELF::R_390_PC24DBL; case SystemZ::FK_390_PC32DBL: return ELF::R_390_PC32DBL; } reportError(Loc, "Unsupported PC-relative address"); return 0; } unsigned SystemZELFObjectWriter::getRelocType(const MCFixup &Fixup, const MCValue &Target, bool IsPCRel) const { SMLoc Loc = Fixup.getLoc(); unsigned Kind = Fixup.getKind(); auto Specifier = SystemZ::Specifier(Target.getSpecifier()); switch (Specifier) { case SystemZ::S_INDNTPOFF: case SystemZ::S_NTPOFF: case SystemZ::S_TLSGD: case SystemZ::S_TLSLD: case SystemZ::S_TLSLDM: case SystemZ::S_DTPOFF: if (auto *SA = Target.getAddSym()) cast(SA)->setType(ELF::STT_TLS); break; default: break; } switch (Specifier) { case SystemZ::S_None: if (IsPCRel) return getPCRelReloc(Loc, Kind); return getAbsoluteReloc(Loc, Kind); case SystemZ::S_NTPOFF: assert(!IsPCRel && "NTPOFF shouldn't be PC-relative"); switch (Kind) { case FK_Data_4: return ELF::R_390_TLS_LE32; case FK_Data_8: return ELF::R_390_TLS_LE64; } reportError(Loc, "Unsupported thread-local address (local-exec)"); return 0; case SystemZ::S_INDNTPOFF: if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) return ELF::R_390_TLS_IEENT; reportError(Loc, "Only PC-relative INDNTPOFF accesses are supported for now"); return 0; case SystemZ::S_DTPOFF: assert(!IsPCRel && "DTPOFF shouldn't be PC-relative"); switch (Kind) { case FK_Data_4: return ELF::R_390_TLS_LDO32; case FK_Data_8: return ELF::R_390_TLS_LDO64; } reportError(Loc, "Unsupported thread-local address (local-dynamic)"); return 0; case SystemZ::S_TLSLDM: assert(!IsPCRel && "TLSLDM shouldn't be PC-relative"); switch (Kind) { case FK_Data_4: return ELF::R_390_TLS_LDM32; case FK_Data_8: return ELF::R_390_TLS_LDM64; case SystemZ::FK_390_TLS_CALL: return ELF::R_390_TLS_LDCALL; } reportError(Loc, "Unsupported thread-local address (local-dynamic)"); return 0; case SystemZ::S_TLSGD: assert(!IsPCRel && "TLSGD shouldn't be PC-relative"); switch (Kind) { case FK_Data_4: return ELF::R_390_TLS_GD32; case FK_Data_8: return ELF::R_390_TLS_GD64; case SystemZ::FK_390_TLS_CALL: return ELF::R_390_TLS_GDCALL; } reportError(Loc, "Unsupported thread-local address (general-dynamic)"); return 0; case SystemZ::S_GOT: case SystemZ::S_GOTENT: if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) return ELF::R_390_GOTENT; reportError(Loc, "Only PC-relative GOT accesses are supported for now"); return 0; case SystemZ::S_PLT: assert(IsPCRel && "@PLT shouldn't be PC-relative"); switch (Kind) { case SystemZ::FK_390_PC12DBL: return ELF::R_390_PLT12DBL; case SystemZ::FK_390_PC16DBL: return ELF::R_390_PLT16DBL; case SystemZ::FK_390_PC24DBL: return ELF::R_390_PLT24DBL; case SystemZ::FK_390_PC32DBL: return ELF::R_390_PLT32DBL; } reportError(Loc, "Unsupported PC-relative PLT address"); return 0; default: llvm_unreachable("Modifier not supported"); } } bool SystemZELFObjectWriter::needsRelocateWithSymbol(const MCValue &V, unsigned Type) const { switch (V.getSpecifier()) { case SystemZ::S_GOT: case SystemZ::S_PLT: return true; default: return false; } } std::unique_ptr llvm::createSystemZELFObjectWriter(uint8_t OSABI) { return std::make_unique(OSABI); }