10b57cec5SDimitry Andric //===-- SystemZMCAsmBackend.cpp - SystemZ assembler backend ---------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "MCTargetDesc/SystemZMCFixups.h" 100b57cec5SDimitry Andric #include "MCTargetDesc/SystemZMCTargetDesc.h" 11fe6060f1SDimitry Andric #include "llvm/ADT/StringSwitch.h" 120b57cec5SDimitry Andric #include "llvm/MC/MCAsmBackend.h" 13349cc55cSDimitry Andric #include "llvm/MC/MCAssembler.h" 14349cc55cSDimitry Andric #include "llvm/MC/MCContext.h" 150b57cec5SDimitry Andric #include "llvm/MC/MCELFObjectWriter.h" 160b57cec5SDimitry Andric #include "llvm/MC/MCFixupKindInfo.h" 170b57cec5SDimitry Andric #include "llvm/MC/MCInst.h" 180b57cec5SDimitry Andric #include "llvm/MC/MCObjectWriter.h" 190b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h" 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric using namespace llvm; 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric // Value is a fully-resolved relocation value: Symbol + Addend [- Pivot]. 240b57cec5SDimitry Andric // Return the bits that should be installed in a relocation field for 250b57cec5SDimitry Andric // fixup kind Kind. 26349cc55cSDimitry Andric static uint64_t extractBitsForFixup(MCFixupKind Kind, uint64_t Value, 27349cc55cSDimitry Andric const MCFixup &Fixup, MCContext &Ctx) { 280b57cec5SDimitry Andric if (Kind < FirstTargetFixupKind) 290b57cec5SDimitry Andric return Value; 300b57cec5SDimitry Andric 310eae32dcSDimitry Andric auto checkFixupInRange = [&](int64_t Min, int64_t Max) -> bool { 320eae32dcSDimitry Andric int64_t SVal = int64_t(Value); 330eae32dcSDimitry Andric if (SVal < Min || SVal > Max) { 340eae32dcSDimitry Andric Ctx.reportError(Fixup.getLoc(), "operand out of range (" + Twine(SVal) + 350eae32dcSDimitry Andric " not between " + Twine(Min) + 360eae32dcSDimitry Andric " and " + Twine(Max) + ")"); 370eae32dcSDimitry Andric return false; 380eae32dcSDimitry Andric } 390eae32dcSDimitry Andric return true; 400eae32dcSDimitry Andric }; 410eae32dcSDimitry Andric 420eae32dcSDimitry Andric auto handlePCRelFixupValue = [&](unsigned W) -> uint64_t { 430eae32dcSDimitry Andric if (Value % 2 != 0) 440eae32dcSDimitry Andric Ctx.reportError(Fixup.getLoc(), "Non-even PC relative offset."); 450eae32dcSDimitry Andric if (!checkFixupInRange(minIntN(W) * 2, maxIntN(W) * 2)) 460eae32dcSDimitry Andric return 0; 470eae32dcSDimitry Andric return (int64_t)Value / 2; 480eae32dcSDimitry Andric }; 490eae32dcSDimitry Andric 5006c3fb27SDimitry Andric auto handleImmValue = [&](bool IsSigned, unsigned W) -> uint64_t { 5106c3fb27SDimitry Andric if (!(IsSigned ? checkFixupInRange(minIntN(W), maxIntN(W)) 5206c3fb27SDimitry Andric : checkFixupInRange(0, maxUIntN(W)))) 5306c3fb27SDimitry Andric return 0; 5406c3fb27SDimitry Andric return Value; 5506c3fb27SDimitry Andric }; 5606c3fb27SDimitry Andric 570b57cec5SDimitry Andric switch (unsigned(Kind)) { 580b57cec5SDimitry Andric case SystemZ::FK_390_PC12DBL: 590eae32dcSDimitry Andric return handlePCRelFixupValue(12); 600b57cec5SDimitry Andric case SystemZ::FK_390_PC16DBL: 610eae32dcSDimitry Andric return handlePCRelFixupValue(16); 620b57cec5SDimitry Andric case SystemZ::FK_390_PC24DBL: 630eae32dcSDimitry Andric return handlePCRelFixupValue(24); 640b57cec5SDimitry Andric case SystemZ::FK_390_PC32DBL: 650eae32dcSDimitry Andric return handlePCRelFixupValue(32); 660b57cec5SDimitry Andric 6706c3fb27SDimitry Andric case SystemZ::FK_390_TLS_CALL: 68349cc55cSDimitry Andric return 0; 69349cc55cSDimitry Andric 7006c3fb27SDimitry Andric case SystemZ::FK_390_S8Imm: 7106c3fb27SDimitry Andric return handleImmValue(true, 8); 7206c3fb27SDimitry Andric case SystemZ::FK_390_S16Imm: 7306c3fb27SDimitry Andric return handleImmValue(true, 16); 7406c3fb27SDimitry Andric case SystemZ::FK_390_S20Imm: { 7506c3fb27SDimitry Andric Value = handleImmValue(true, 20); 7606c3fb27SDimitry Andric // S20Imm is used only for signed 20-bit displacements. 77349cc55cSDimitry Andric // The high byte of a 20 bit displacement value comes first. 78349cc55cSDimitry Andric uint64_t DLo = Value & 0xfff; 79349cc55cSDimitry Andric uint64_t DHi = (Value >> 12) & 0xff; 80349cc55cSDimitry Andric return (DLo << 8) | DHi; 81349cc55cSDimitry Andric } 8206c3fb27SDimitry Andric case SystemZ::FK_390_S32Imm: 8306c3fb27SDimitry Andric return handleImmValue(true, 32); 8406c3fb27SDimitry Andric case SystemZ::FK_390_U1Imm: 8506c3fb27SDimitry Andric return handleImmValue(false, 1); 8606c3fb27SDimitry Andric case SystemZ::FK_390_U2Imm: 8706c3fb27SDimitry Andric return handleImmValue(false, 2); 8806c3fb27SDimitry Andric case SystemZ::FK_390_U3Imm: 8906c3fb27SDimitry Andric return handleImmValue(false, 3); 9006c3fb27SDimitry Andric case SystemZ::FK_390_U4Imm: 9106c3fb27SDimitry Andric return handleImmValue(false, 4); 9206c3fb27SDimitry Andric case SystemZ::FK_390_U8Imm: 9306c3fb27SDimitry Andric return handleImmValue(false, 8); 9406c3fb27SDimitry Andric case SystemZ::FK_390_U12Imm: 9506c3fb27SDimitry Andric return handleImmValue(false, 12); 9606c3fb27SDimitry Andric case SystemZ::FK_390_U16Imm: 9706c3fb27SDimitry Andric return handleImmValue(false, 16); 9806c3fb27SDimitry Andric case SystemZ::FK_390_U32Imm: 9906c3fb27SDimitry Andric return handleImmValue(false, 32); 10006c3fb27SDimitry Andric case SystemZ::FK_390_U48Imm: 10106c3fb27SDimitry Andric return handleImmValue(false, 48); 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric llvm_unreachable("Unknown fixup kind!"); 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric namespace { 1080b57cec5SDimitry Andric class SystemZMCAsmBackend : public MCAsmBackend { 1090b57cec5SDimitry Andric public: 110*5f757f3fSDimitry Andric SystemZMCAsmBackend() : MCAsmBackend(llvm::endianness::big) {} 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric // Override MCAsmBackend 1130b57cec5SDimitry Andric unsigned getNumFixupKinds() const override { 1140b57cec5SDimitry Andric return SystemZ::NumTargetFixupKinds; 1150b57cec5SDimitry Andric } 116bdd1243dSDimitry Andric std::optional<MCFixupKind> getFixupKind(StringRef Name) const override; 1170b57cec5SDimitry Andric const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; 118fe6060f1SDimitry Andric bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, 119*5f757f3fSDimitry Andric const MCValue &Target, 120*5f757f3fSDimitry Andric const MCSubtargetInfo *STI) override; 1210b57cec5SDimitry Andric void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 1220b57cec5SDimitry Andric const MCValue &Target, MutableArrayRef<char> Data, 1230b57cec5SDimitry Andric uint64_t Value, bool IsResolved, 1240b57cec5SDimitry Andric const MCSubtargetInfo *STI) const override; 125349cc55cSDimitry Andric bool writeNopData(raw_ostream &OS, uint64_t Count, 126349cc55cSDimitry Andric const MCSubtargetInfo *STI) const override; 1270b57cec5SDimitry Andric }; 1280b57cec5SDimitry Andric } // end anonymous namespace 1290b57cec5SDimitry Andric 130bdd1243dSDimitry Andric std::optional<MCFixupKind> 131bdd1243dSDimitry Andric SystemZMCAsmBackend::getFixupKind(StringRef Name) const { 132fe6060f1SDimitry Andric unsigned Type = llvm::StringSwitch<unsigned>(Name) 133fe6060f1SDimitry Andric #define ELF_RELOC(X, Y) .Case(#X, Y) 134fe6060f1SDimitry Andric #include "llvm/BinaryFormat/ELFRelocs/SystemZ.def" 135fe6060f1SDimitry Andric #undef ELF_RELOC 136fe6060f1SDimitry Andric .Case("BFD_RELOC_NONE", ELF::R_390_NONE) 137fe6060f1SDimitry Andric .Case("BFD_RELOC_8", ELF::R_390_8) 138fe6060f1SDimitry Andric .Case("BFD_RELOC_16", ELF::R_390_16) 139fe6060f1SDimitry Andric .Case("BFD_RELOC_32", ELF::R_390_32) 140fe6060f1SDimitry Andric .Case("BFD_RELOC_64", ELF::R_390_64) 141fe6060f1SDimitry Andric .Default(-1u); 142fe6060f1SDimitry Andric if (Type != -1u) 143fe6060f1SDimitry Andric return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type); 144bdd1243dSDimitry Andric return std::nullopt; 145fe6060f1SDimitry Andric } 146fe6060f1SDimitry Andric 1470b57cec5SDimitry Andric const MCFixupKindInfo & 1480b57cec5SDimitry Andric SystemZMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { 149fe6060f1SDimitry Andric // Fixup kinds from .reloc directive are like R_390_NONE. They 150fe6060f1SDimitry Andric // do not require any extra processing. 151fe6060f1SDimitry Andric if (Kind >= FirstLiteralRelocationKind) 152fe6060f1SDimitry Andric return MCAsmBackend::getFixupKindInfo(FK_NONE); 153fe6060f1SDimitry Andric 1540b57cec5SDimitry Andric if (Kind < FirstTargetFixupKind) 1550b57cec5SDimitry Andric return MCAsmBackend::getFixupKindInfo(Kind); 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 1580b57cec5SDimitry Andric "Invalid kind!"); 15906c3fb27SDimitry Andric return SystemZ::MCFixupKindInfos[Kind - FirstTargetFixupKind]; 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 162fe6060f1SDimitry Andric bool SystemZMCAsmBackend::shouldForceRelocation(const MCAssembler &, 163fe6060f1SDimitry Andric const MCFixup &Fixup, 164*5f757f3fSDimitry Andric const MCValue &, 165*5f757f3fSDimitry Andric const MCSubtargetInfo *STI) { 166fe6060f1SDimitry Andric return Fixup.getKind() >= FirstLiteralRelocationKind; 167fe6060f1SDimitry Andric } 168fe6060f1SDimitry Andric 1690b57cec5SDimitry Andric void SystemZMCAsmBackend::applyFixup(const MCAssembler &Asm, 1700b57cec5SDimitry Andric const MCFixup &Fixup, 1710b57cec5SDimitry Andric const MCValue &Target, 1720b57cec5SDimitry Andric MutableArrayRef<char> Data, uint64_t Value, 1730b57cec5SDimitry Andric bool IsResolved, 1740b57cec5SDimitry Andric const MCSubtargetInfo *STI) const { 1750b57cec5SDimitry Andric MCFixupKind Kind = Fixup.getKind(); 176fe6060f1SDimitry Andric if (Kind >= FirstLiteralRelocationKind) 177fe6060f1SDimitry Andric return; 1780b57cec5SDimitry Andric unsigned Offset = Fixup.getOffset(); 1790b57cec5SDimitry Andric unsigned BitSize = getFixupKindInfo(Kind).TargetSize; 1800b57cec5SDimitry Andric unsigned Size = (BitSize + 7) / 8; 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric assert(Offset + Size <= Data.size() && "Invalid fixup offset!"); 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric // Big-endian insertion of Size bytes. 185349cc55cSDimitry Andric Value = extractBitsForFixup(Kind, Value, Fixup, Asm.getContext()); 1860b57cec5SDimitry Andric if (BitSize < 64) 1870b57cec5SDimitry Andric Value &= ((uint64_t)1 << BitSize) - 1; 1880b57cec5SDimitry Andric unsigned ShiftValue = (Size * 8) - 8; 1890b57cec5SDimitry Andric for (unsigned I = 0; I != Size; ++I) { 1900b57cec5SDimitry Andric Data[Offset + I] |= uint8_t(Value >> ShiftValue); 1910b57cec5SDimitry Andric ShiftValue -= 8; 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric } 1940b57cec5SDimitry Andric 195349cc55cSDimitry Andric bool SystemZMCAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, 196349cc55cSDimitry Andric const MCSubtargetInfo *STI) const { 1970b57cec5SDimitry Andric for (uint64_t I = 0; I != Count; ++I) 1980b57cec5SDimitry Andric OS << '\x7'; 1990b57cec5SDimitry Andric return true; 2000b57cec5SDimitry Andric } 2010b57cec5SDimitry Andric 202*5f757f3fSDimitry Andric namespace { 203*5f757f3fSDimitry Andric class ELFSystemZAsmBackend : public SystemZMCAsmBackend { 204*5f757f3fSDimitry Andric uint8_t OSABI; 205*5f757f3fSDimitry Andric 206*5f757f3fSDimitry Andric public: 207*5f757f3fSDimitry Andric ELFSystemZAsmBackend(uint8_t OsABI) : SystemZMCAsmBackend(), OSABI(OsABI){}; 208*5f757f3fSDimitry Andric 209*5f757f3fSDimitry Andric std::unique_ptr<MCObjectTargetWriter> 210*5f757f3fSDimitry Andric createObjectTargetWriter() const override { 211*5f757f3fSDimitry Andric return createSystemZELFObjectWriter(OSABI); 212*5f757f3fSDimitry Andric } 213*5f757f3fSDimitry Andric }; 214*5f757f3fSDimitry Andric 215*5f757f3fSDimitry Andric class GOFFSystemZAsmBackend : public SystemZMCAsmBackend { 216*5f757f3fSDimitry Andric public: 217*5f757f3fSDimitry Andric GOFFSystemZAsmBackend() : SystemZMCAsmBackend(){}; 218*5f757f3fSDimitry Andric 219*5f757f3fSDimitry Andric std::unique_ptr<MCObjectTargetWriter> 220*5f757f3fSDimitry Andric createObjectTargetWriter() const override { 221*5f757f3fSDimitry Andric return createSystemZGOFFObjectWriter(); 222*5f757f3fSDimitry Andric } 223*5f757f3fSDimitry Andric }; 224*5f757f3fSDimitry Andric } // namespace 225*5f757f3fSDimitry Andric 2260b57cec5SDimitry Andric MCAsmBackend *llvm::createSystemZMCAsmBackend(const Target &T, 2270b57cec5SDimitry Andric const MCSubtargetInfo &STI, 2280b57cec5SDimitry Andric const MCRegisterInfo &MRI, 2290b57cec5SDimitry Andric const MCTargetOptions &Options) { 230*5f757f3fSDimitry Andric if (STI.getTargetTriple().isOSzOS()) { 231*5f757f3fSDimitry Andric return new GOFFSystemZAsmBackend(); 232*5f757f3fSDimitry Andric } 233*5f757f3fSDimitry Andric 2340b57cec5SDimitry Andric uint8_t OSABI = 2350b57cec5SDimitry Andric MCELFObjectTargetWriter::getOSABI(STI.getTargetTriple().getOS()); 236*5f757f3fSDimitry Andric return new ELFSystemZAsmBackend(OSABI); 2370b57cec5SDimitry Andric } 238