221 lines · cpp
1//===-- SystemZMCAsmBackend.cpp - SystemZ assembler backend ---------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "MCTargetDesc/SystemZMCFixups.h"10#include "MCTargetDesc/SystemZMCTargetDesc.h"11#include "llvm/ADT/StringSwitch.h"12#include "llvm/MC/MCAsmBackend.h"13#include "llvm/MC/MCAssembler.h"14#include "llvm/MC/MCContext.h"15#include "llvm/MC/MCELFObjectWriter.h"16#include "llvm/MC/MCInst.h"17#include "llvm/MC/MCObjectWriter.h"18#include "llvm/MC/MCSubtargetInfo.h"19#include "llvm/MC/MCValue.h"20 21using namespace llvm;22 23// Value is a fully-resolved relocation value: Symbol + Addend [- Pivot].24// Return the bits that should be installed in a relocation field for25// fixup kind Kind.26static uint64_t extractBitsForFixup(MCFixupKind Kind, uint64_t Value,27 const MCFixup &Fixup, MCContext &Ctx) {28 if (Kind < FirstTargetFixupKind)29 return Value;30 31 auto checkFixupInRange = [&](int64_t Min, int64_t Max) -> bool {32 int64_t SVal = int64_t(Value);33 if (SVal < Min || SVal > Max) {34 Ctx.reportError(Fixup.getLoc(), "operand out of range (" + Twine(SVal) +35 " not between " + Twine(Min) +36 " and " + Twine(Max) + ")");37 return false;38 }39 return true;40 };41 42 auto handlePCRelFixupValue = [&](unsigned W) -> uint64_t {43 if (Value % 2 != 0)44 Ctx.reportError(Fixup.getLoc(), "Non-even PC relative offset.");45 if (!checkFixupInRange(minIntN(W) * 2, maxIntN(W) * 2))46 return 0;47 return (int64_t)Value / 2;48 };49 50 auto handleImmValue = [&](bool IsSigned, unsigned W) -> uint64_t {51 if (!(IsSigned ? checkFixupInRange(minIntN(W), maxIntN(W))52 : checkFixupInRange(0, maxUIntN(W))))53 return 0;54 return Value;55 };56 57 switch (unsigned(Kind)) {58 case SystemZ::FK_390_PC12DBL:59 return handlePCRelFixupValue(12);60 case SystemZ::FK_390_PC16DBL:61 return handlePCRelFixupValue(16);62 case SystemZ::FK_390_PC24DBL:63 return handlePCRelFixupValue(24);64 case SystemZ::FK_390_PC32DBL:65 return handlePCRelFixupValue(32);66 67 case SystemZ::FK_390_TLS_CALL:68 return 0;69 70 case SystemZ::FK_390_S8Imm:71 return handleImmValue(true, 8);72 case SystemZ::FK_390_S16Imm:73 return handleImmValue(true, 16);74 case SystemZ::FK_390_S20Imm: {75 Value = handleImmValue(true, 20);76 // S20Imm is used only for signed 20-bit displacements.77 // The high byte of a 20 bit displacement value comes first.78 uint64_t DLo = Value & 0xfff;79 uint64_t DHi = (Value >> 12) & 0xff;80 return (DLo << 8) | DHi;81 }82 case SystemZ::FK_390_S32Imm:83 return handleImmValue(true, 32);84 case SystemZ::FK_390_U1Imm:85 return handleImmValue(false, 1);86 case SystemZ::FK_390_U2Imm:87 return handleImmValue(false, 2);88 case SystemZ::FK_390_U3Imm:89 return handleImmValue(false, 3);90 case SystemZ::FK_390_U4Imm:91 return handleImmValue(false, 4);92 case SystemZ::FK_390_U8Imm:93 return handleImmValue(false, 8);94 case SystemZ::FK_390_U12Imm:95 return handleImmValue(false, 12);96 case SystemZ::FK_390_U16Imm:97 return handleImmValue(false, 16);98 case SystemZ::FK_390_U32Imm:99 return handleImmValue(false, 32);100 case SystemZ::FK_390_U48Imm:101 return handleImmValue(false, 48);102 }103 104 llvm_unreachable("Unknown fixup kind!");105}106 107namespace {108class SystemZMCAsmBackend : public MCAsmBackend {109public:110 SystemZMCAsmBackend() : MCAsmBackend(llvm::endianness::big) {}111 112 // Override MCAsmBackend113 std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;114 MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const override;115 void applyFixup(const MCFragment &, const MCFixup &, const MCValue &Target,116 uint8_t *Data, uint64_t Value, bool IsResolved) override;117 bool writeNopData(raw_ostream &OS, uint64_t Count,118 const MCSubtargetInfo *STI) const override;119};120} // end anonymous namespace121 122std::optional<MCFixupKind>123SystemZMCAsmBackend::getFixupKind(StringRef Name) const {124 unsigned Type = llvm::StringSwitch<unsigned>(Name)125#define ELF_RELOC(X, Y) .Case(#X, Y)126#include "llvm/BinaryFormat/ELFRelocs/SystemZ.def"127#undef ELF_RELOC128 .Case("BFD_RELOC_NONE", ELF::R_390_NONE)129 .Case("BFD_RELOC_8", ELF::R_390_8)130 .Case("BFD_RELOC_16", ELF::R_390_16)131 .Case("BFD_RELOC_32", ELF::R_390_32)132 .Case("BFD_RELOC_64", ELF::R_390_64)133 .Default(-1u);134 if (Type != -1u)135 return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);136 return std::nullopt;137}138 139MCFixupKindInfo SystemZMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {140 // Fixup kinds from .reloc directive are like R_390_NONE. They141 // do not require any extra processing.142 if (mc::isRelocation(Kind))143 return {};144 145 if (Kind < FirstTargetFixupKind)146 return MCAsmBackend::getFixupKindInfo(Kind);147 148 assert(unsigned(Kind - FirstTargetFixupKind) < SystemZ::NumTargetFixupKinds &&149 "Invalid kind!");150 return SystemZ::MCFixupKindInfos[Kind - FirstTargetFixupKind];151}152 153void SystemZMCAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,154 const MCValue &Target, uint8_t *Data,155 uint64_t Value, bool IsResolved) {156 if (Target.getSpecifier())157 IsResolved = false;158 maybeAddReloc(F, Fixup, Target, Value, IsResolved);159 MCFixupKind Kind = Fixup.getKind();160 if (mc::isRelocation(Kind))161 return;162 unsigned BitSize = getFixupKindInfo(Kind).TargetSize;163 unsigned Size = (BitSize + 7) / 8;164 165 assert(Fixup.getOffset() + Size <= F.getSize() && "Invalid fixup offset!");166 167 // Big-endian insertion of Size bytes.168 Value = extractBitsForFixup(Kind, Value, Fixup, getContext());169 if (BitSize < 64)170 Value &= ((uint64_t)1 << BitSize) - 1;171 unsigned ShiftValue = (Size * 8) - 8;172 for (unsigned I = 0; I != Size; ++I) {173 Data[I] |= uint8_t(Value >> ShiftValue);174 ShiftValue -= 8;175 }176}177 178bool SystemZMCAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,179 const MCSubtargetInfo *STI) const {180 for (uint64_t I = 0; I != Count; ++I)181 OS << '\x7';182 return true;183}184 185namespace {186class ELFSystemZAsmBackend : public SystemZMCAsmBackend {187 uint8_t OSABI;188 189public:190 ELFSystemZAsmBackend(uint8_t OsABI) : SystemZMCAsmBackend(), OSABI(OsABI){};191 192 std::unique_ptr<MCObjectTargetWriter>193 createObjectTargetWriter() const override {194 return createSystemZELFObjectWriter(OSABI);195 }196};197 198class GOFFSystemZAsmBackend : public SystemZMCAsmBackend {199public:200 GOFFSystemZAsmBackend() : SystemZMCAsmBackend(){};201 202 std::unique_ptr<MCObjectTargetWriter>203 createObjectTargetWriter() const override {204 return createSystemZGOFFObjectWriter();205 }206};207} // namespace208 209MCAsmBackend *llvm::createSystemZMCAsmBackend(const Target &T,210 const MCSubtargetInfo &STI,211 const MCRegisterInfo &MRI,212 const MCTargetOptions &Options) {213 if (STI.getTargetTriple().isOSzOS()) {214 return new GOFFSystemZAsmBackend();215 }216 217 uint8_t OSABI =218 MCELFObjectTargetWriter::getOSABI(STI.getTargetTriple().getOS());219 return new ELFSystemZAsmBackend(OSABI);220}221