Path: blob/main/contrib/llvm-project/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
35294 views
//===-- SystemZMCAsmBackend.cpp - SystemZ assembler backend ---------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "MCTargetDesc/SystemZMCFixups.h"9#include "MCTargetDesc/SystemZMCTargetDesc.h"10#include "llvm/ADT/StringSwitch.h"11#include "llvm/MC/MCAsmBackend.h"12#include "llvm/MC/MCAssembler.h"13#include "llvm/MC/MCContext.h"14#include "llvm/MC/MCELFObjectWriter.h"15#include "llvm/MC/MCFixupKindInfo.h"16#include "llvm/MC/MCInst.h"17#include "llvm/MC/MCObjectWriter.h"18#include "llvm/MC/MCSubtargetInfo.h"1920using namespace llvm;2122// Value is a fully-resolved relocation value: Symbol + Addend [- Pivot].23// Return the bits that should be installed in a relocation field for24// fixup kind Kind.25static uint64_t extractBitsForFixup(MCFixupKind Kind, uint64_t Value,26const MCFixup &Fixup, MCContext &Ctx) {27if (Kind < FirstTargetFixupKind)28return Value;2930auto checkFixupInRange = [&](int64_t Min, int64_t Max) -> bool {31int64_t SVal = int64_t(Value);32if (SVal < Min || SVal > Max) {33Ctx.reportError(Fixup.getLoc(), "operand out of range (" + Twine(SVal) +34" not between " + Twine(Min) +35" and " + Twine(Max) + ")");36return false;37}38return true;39};4041auto handlePCRelFixupValue = [&](unsigned W) -> uint64_t {42if (Value % 2 != 0)43Ctx.reportError(Fixup.getLoc(), "Non-even PC relative offset.");44if (!checkFixupInRange(minIntN(W) * 2, maxIntN(W) * 2))45return 0;46return (int64_t)Value / 2;47};4849auto handleImmValue = [&](bool IsSigned, unsigned W) -> uint64_t {50if (!(IsSigned ? checkFixupInRange(minIntN(W), maxIntN(W))51: checkFixupInRange(0, maxUIntN(W))))52return 0;53return Value;54};5556switch (unsigned(Kind)) {57case SystemZ::FK_390_PC12DBL:58return handlePCRelFixupValue(12);59case SystemZ::FK_390_PC16DBL:60return handlePCRelFixupValue(16);61case SystemZ::FK_390_PC24DBL:62return handlePCRelFixupValue(24);63case SystemZ::FK_390_PC32DBL:64return handlePCRelFixupValue(32);6566case SystemZ::FK_390_TLS_CALL:67return 0;6869case SystemZ::FK_390_S8Imm:70return handleImmValue(true, 8);71case SystemZ::FK_390_S16Imm:72return handleImmValue(true, 16);73case SystemZ::FK_390_S20Imm: {74Value = handleImmValue(true, 20);75// S20Imm is used only for signed 20-bit displacements.76// The high byte of a 20 bit displacement value comes first.77uint64_t DLo = Value & 0xfff;78uint64_t DHi = (Value >> 12) & 0xff;79return (DLo << 8) | DHi;80}81case SystemZ::FK_390_S32Imm:82return handleImmValue(true, 32);83case SystemZ::FK_390_U1Imm:84return handleImmValue(false, 1);85case SystemZ::FK_390_U2Imm:86return handleImmValue(false, 2);87case SystemZ::FK_390_U3Imm:88return handleImmValue(false, 3);89case SystemZ::FK_390_U4Imm:90return handleImmValue(false, 4);91case SystemZ::FK_390_U8Imm:92return handleImmValue(false, 8);93case SystemZ::FK_390_U12Imm:94return handleImmValue(false, 12);95case SystemZ::FK_390_U16Imm:96return handleImmValue(false, 16);97case SystemZ::FK_390_U32Imm:98return handleImmValue(false, 32);99case SystemZ::FK_390_U48Imm:100return handleImmValue(false, 48);101}102103llvm_unreachable("Unknown fixup kind!");104}105106namespace {107class SystemZMCAsmBackend : public MCAsmBackend {108public:109SystemZMCAsmBackend() : MCAsmBackend(llvm::endianness::big) {}110111// Override MCAsmBackend112unsigned getNumFixupKinds() const override {113return SystemZ::NumTargetFixupKinds;114}115std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;116const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;117bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,118const MCValue &Target,119const MCSubtargetInfo *STI) override;120void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,121const MCValue &Target, MutableArrayRef<char> Data,122uint64_t Value, bool IsResolved,123const MCSubtargetInfo *STI) const override;124bool writeNopData(raw_ostream &OS, uint64_t Count,125const MCSubtargetInfo *STI) const override;126};127} // end anonymous namespace128129std::optional<MCFixupKind>130SystemZMCAsmBackend::getFixupKind(StringRef Name) const {131unsigned Type = llvm::StringSwitch<unsigned>(Name)132#define ELF_RELOC(X, Y) .Case(#X, Y)133#include "llvm/BinaryFormat/ELFRelocs/SystemZ.def"134#undef ELF_RELOC135.Case("BFD_RELOC_NONE", ELF::R_390_NONE)136.Case("BFD_RELOC_8", ELF::R_390_8)137.Case("BFD_RELOC_16", ELF::R_390_16)138.Case("BFD_RELOC_32", ELF::R_390_32)139.Case("BFD_RELOC_64", ELF::R_390_64)140.Default(-1u);141if (Type != -1u)142return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);143return std::nullopt;144}145146const MCFixupKindInfo &147SystemZMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {148// Fixup kinds from .reloc directive are like R_390_NONE. They149// do not require any extra processing.150if (Kind >= FirstLiteralRelocationKind)151return MCAsmBackend::getFixupKindInfo(FK_NONE);152153if (Kind < FirstTargetFixupKind)154return MCAsmBackend::getFixupKindInfo(Kind);155156assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&157"Invalid kind!");158return SystemZ::MCFixupKindInfos[Kind - FirstTargetFixupKind];159}160161bool SystemZMCAsmBackend::shouldForceRelocation(const MCAssembler &,162const MCFixup &Fixup,163const MCValue &,164const MCSubtargetInfo *STI) {165return Fixup.getKind() >= FirstLiteralRelocationKind;166}167168void SystemZMCAsmBackend::applyFixup(const MCAssembler &Asm,169const MCFixup &Fixup,170const MCValue &Target,171MutableArrayRef<char> Data, uint64_t Value,172bool IsResolved,173const MCSubtargetInfo *STI) const {174MCFixupKind Kind = Fixup.getKind();175if (Kind >= FirstLiteralRelocationKind)176return;177unsigned Offset = Fixup.getOffset();178unsigned BitSize = getFixupKindInfo(Kind).TargetSize;179unsigned Size = (BitSize + 7) / 8;180181assert(Offset + Size <= Data.size() && "Invalid fixup offset!");182183// Big-endian insertion of Size bytes.184Value = extractBitsForFixup(Kind, Value, Fixup, Asm.getContext());185if (BitSize < 64)186Value &= ((uint64_t)1 << BitSize) - 1;187unsigned ShiftValue = (Size * 8) - 8;188for (unsigned I = 0; I != Size; ++I) {189Data[Offset + I] |= uint8_t(Value >> ShiftValue);190ShiftValue -= 8;191}192}193194bool SystemZMCAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,195const MCSubtargetInfo *STI) const {196for (uint64_t I = 0; I != Count; ++I)197OS << '\x7';198return true;199}200201namespace {202class ELFSystemZAsmBackend : public SystemZMCAsmBackend {203uint8_t OSABI;204205public:206ELFSystemZAsmBackend(uint8_t OsABI) : SystemZMCAsmBackend(), OSABI(OsABI){};207208std::unique_ptr<MCObjectTargetWriter>209createObjectTargetWriter() const override {210return createSystemZELFObjectWriter(OSABI);211}212};213214class GOFFSystemZAsmBackend : public SystemZMCAsmBackend {215public:216GOFFSystemZAsmBackend() : SystemZMCAsmBackend(){};217218std::unique_ptr<MCObjectTargetWriter>219createObjectTargetWriter() const override {220return createSystemZGOFFObjectWriter();221}222};223} // namespace224225MCAsmBackend *llvm::createSystemZMCAsmBackend(const Target &T,226const MCSubtargetInfo &STI,227const MCRegisterInfo &MRI,228const MCTargetOptions &Options) {229if (STI.getTargetTriple().isOSzOS()) {230return new GOFFSystemZAsmBackend();231}232233uint8_t OSABI =234MCELFObjectTargetWriter::getOSABI(STI.getTargetTriple().getOS());235return new ELFSystemZAsmBackend(OSABI);236}237238239