We will increase the use of raw relocation types and eliminate fixup kinds that correspond to relocation types. The getFixupKindInfo functions will return an rvalue instead. Let's update the return type from a const reference to a value type.
224 lines
7.5 KiB
C++
224 lines
7.5 KiB
C++
//===-- SystemZMCAsmBackend.cpp - SystemZ assembler backend ---------------===//
|
|
//
|
|
// 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/SystemZMCFixups.h"
|
|
#include "MCTargetDesc/SystemZMCTargetDesc.h"
|
|
#include "llvm/ADT/StringSwitch.h"
|
|
#include "llvm/MC/MCAsmBackend.h"
|
|
#include "llvm/MC/MCAssembler.h"
|
|
#include "llvm/MC/MCContext.h"
|
|
#include "llvm/MC/MCELFObjectWriter.h"
|
|
#include "llvm/MC/MCFixupKindInfo.h"
|
|
#include "llvm/MC/MCInst.h"
|
|
#include "llvm/MC/MCObjectWriter.h"
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
|
|
|
using namespace llvm;
|
|
|
|
// Value is a fully-resolved relocation value: Symbol + Addend [- Pivot].
|
|
// Return the bits that should be installed in a relocation field for
|
|
// fixup kind Kind.
|
|
static uint64_t extractBitsForFixup(MCFixupKind Kind, uint64_t Value,
|
|
const MCFixup &Fixup, MCContext &Ctx) {
|
|
if (Kind < FirstTargetFixupKind)
|
|
return Value;
|
|
|
|
auto checkFixupInRange = [&](int64_t Min, int64_t Max) -> bool {
|
|
int64_t SVal = int64_t(Value);
|
|
if (SVal < Min || SVal > Max) {
|
|
Ctx.reportError(Fixup.getLoc(), "operand out of range (" + Twine(SVal) +
|
|
" not between " + Twine(Min) +
|
|
" and " + Twine(Max) + ")");
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
auto handlePCRelFixupValue = [&](unsigned W) -> uint64_t {
|
|
if (Value % 2 != 0)
|
|
Ctx.reportError(Fixup.getLoc(), "Non-even PC relative offset.");
|
|
if (!checkFixupInRange(minIntN(W) * 2, maxIntN(W) * 2))
|
|
return 0;
|
|
return (int64_t)Value / 2;
|
|
};
|
|
|
|
auto handleImmValue = [&](bool IsSigned, unsigned W) -> uint64_t {
|
|
if (!(IsSigned ? checkFixupInRange(minIntN(W), maxIntN(W))
|
|
: checkFixupInRange(0, maxUIntN(W))))
|
|
return 0;
|
|
return Value;
|
|
};
|
|
|
|
switch (unsigned(Kind)) {
|
|
case SystemZ::FK_390_PC12DBL:
|
|
return handlePCRelFixupValue(12);
|
|
case SystemZ::FK_390_PC16DBL:
|
|
return handlePCRelFixupValue(16);
|
|
case SystemZ::FK_390_PC24DBL:
|
|
return handlePCRelFixupValue(24);
|
|
case SystemZ::FK_390_PC32DBL:
|
|
return handlePCRelFixupValue(32);
|
|
|
|
case SystemZ::FK_390_TLS_CALL:
|
|
return 0;
|
|
|
|
case SystemZ::FK_390_S8Imm:
|
|
return handleImmValue(true, 8);
|
|
case SystemZ::FK_390_S16Imm:
|
|
return handleImmValue(true, 16);
|
|
case SystemZ::FK_390_S20Imm: {
|
|
Value = handleImmValue(true, 20);
|
|
// S20Imm is used only for signed 20-bit displacements.
|
|
// The high byte of a 20 bit displacement value comes first.
|
|
uint64_t DLo = Value & 0xfff;
|
|
uint64_t DHi = (Value >> 12) & 0xff;
|
|
return (DLo << 8) | DHi;
|
|
}
|
|
case SystemZ::FK_390_S32Imm:
|
|
return handleImmValue(true, 32);
|
|
case SystemZ::FK_390_U1Imm:
|
|
return handleImmValue(false, 1);
|
|
case SystemZ::FK_390_U2Imm:
|
|
return handleImmValue(false, 2);
|
|
case SystemZ::FK_390_U3Imm:
|
|
return handleImmValue(false, 3);
|
|
case SystemZ::FK_390_U4Imm:
|
|
return handleImmValue(false, 4);
|
|
case SystemZ::FK_390_U8Imm:
|
|
return handleImmValue(false, 8);
|
|
case SystemZ::FK_390_U12Imm:
|
|
return handleImmValue(false, 12);
|
|
case SystemZ::FK_390_U16Imm:
|
|
return handleImmValue(false, 16);
|
|
case SystemZ::FK_390_U32Imm:
|
|
return handleImmValue(false, 32);
|
|
case SystemZ::FK_390_U48Imm:
|
|
return handleImmValue(false, 48);
|
|
}
|
|
|
|
llvm_unreachable("Unknown fixup kind!");
|
|
}
|
|
|
|
namespace {
|
|
class SystemZMCAsmBackend : public MCAsmBackend {
|
|
public:
|
|
SystemZMCAsmBackend() : MCAsmBackend(llvm::endianness::big) {}
|
|
|
|
// Override MCAsmBackend
|
|
std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
|
|
MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const override;
|
|
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
|
const MCValue &Target, MutableArrayRef<char> Data,
|
|
uint64_t Value, bool IsResolved,
|
|
const MCSubtargetInfo *STI) const override;
|
|
bool writeNopData(raw_ostream &OS, uint64_t Count,
|
|
const MCSubtargetInfo *STI) const override;
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
std::optional<MCFixupKind>
|
|
SystemZMCAsmBackend::getFixupKind(StringRef Name) const {
|
|
unsigned Type = llvm::StringSwitch<unsigned>(Name)
|
|
#define ELF_RELOC(X, Y) .Case(#X, Y)
|
|
#include "llvm/BinaryFormat/ELFRelocs/SystemZ.def"
|
|
#undef ELF_RELOC
|
|
.Case("BFD_RELOC_NONE", ELF::R_390_NONE)
|
|
.Case("BFD_RELOC_8", ELF::R_390_8)
|
|
.Case("BFD_RELOC_16", ELF::R_390_16)
|
|
.Case("BFD_RELOC_32", ELF::R_390_32)
|
|
.Case("BFD_RELOC_64", ELF::R_390_64)
|
|
.Default(-1u);
|
|
if (Type != -1u)
|
|
return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);
|
|
return std::nullopt;
|
|
}
|
|
|
|
MCFixupKindInfo SystemZMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
|
|
// Fixup kinds from .reloc directive are like R_390_NONE. They
|
|
// do not require any extra processing.
|
|
if (mc::isRelocation(Kind))
|
|
return MCAsmBackend::getFixupKindInfo(FK_NONE);
|
|
|
|
if (Kind < FirstTargetFixupKind)
|
|
return MCAsmBackend::getFixupKindInfo(Kind);
|
|
|
|
assert(unsigned(Kind - FirstTargetFixupKind) < SystemZ::NumTargetFixupKinds &&
|
|
"Invalid kind!");
|
|
return SystemZ::MCFixupKindInfos[Kind - FirstTargetFixupKind];
|
|
}
|
|
|
|
void SystemZMCAsmBackend::applyFixup(const MCAssembler &Asm,
|
|
const MCFixup &Fixup,
|
|
const MCValue &Target,
|
|
MutableArrayRef<char> Data, uint64_t Value,
|
|
bool IsResolved,
|
|
const MCSubtargetInfo *STI) const {
|
|
MCFixupKind Kind = Fixup.getKind();
|
|
if (mc::isRelocation(Kind))
|
|
return;
|
|
unsigned Offset = Fixup.getOffset();
|
|
unsigned BitSize = getFixupKindInfo(Kind).TargetSize;
|
|
unsigned Size = (BitSize + 7) / 8;
|
|
|
|
assert(Offset + Size <= Data.size() && "Invalid fixup offset!");
|
|
|
|
// Big-endian insertion of Size bytes.
|
|
Value = extractBitsForFixup(Kind, Value, Fixup, Asm.getContext());
|
|
if (BitSize < 64)
|
|
Value &= ((uint64_t)1 << BitSize) - 1;
|
|
unsigned ShiftValue = (Size * 8) - 8;
|
|
for (unsigned I = 0; I != Size; ++I) {
|
|
Data[Offset + I] |= uint8_t(Value >> ShiftValue);
|
|
ShiftValue -= 8;
|
|
}
|
|
}
|
|
|
|
bool SystemZMCAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
|
|
const MCSubtargetInfo *STI) const {
|
|
for (uint64_t I = 0; I != Count; ++I)
|
|
OS << '\x7';
|
|
return true;
|
|
}
|
|
|
|
namespace {
|
|
class ELFSystemZAsmBackend : public SystemZMCAsmBackend {
|
|
uint8_t OSABI;
|
|
|
|
public:
|
|
ELFSystemZAsmBackend(uint8_t OsABI) : SystemZMCAsmBackend(), OSABI(OsABI){};
|
|
|
|
std::unique_ptr<MCObjectTargetWriter>
|
|
createObjectTargetWriter() const override {
|
|
return createSystemZELFObjectWriter(OSABI);
|
|
}
|
|
};
|
|
|
|
class GOFFSystemZAsmBackend : public SystemZMCAsmBackend {
|
|
public:
|
|
GOFFSystemZAsmBackend() : SystemZMCAsmBackend(){};
|
|
|
|
std::unique_ptr<MCObjectTargetWriter>
|
|
createObjectTargetWriter() const override {
|
|
return createSystemZGOFFObjectWriter();
|
|
}
|
|
};
|
|
} // namespace
|
|
|
|
MCAsmBackend *llvm::createSystemZMCAsmBackend(const Target &T,
|
|
const MCSubtargetInfo &STI,
|
|
const MCRegisterInfo &MRI,
|
|
const MCTargetOptions &Options) {
|
|
if (STI.getTargetTriple().isOSzOS()) {
|
|
return new GOFFSystemZAsmBackend();
|
|
}
|
|
|
|
uint8_t OSABI =
|
|
MCELFObjectTargetWriter::getOSABI(STI.getTargetTriple().getOS());
|
|
return new ELFSystemZAsmBackend(OSABI);
|
|
}
|