Path: blob/main/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
35294 views
//===-- PPCAsmBackend.cpp - PPC 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/PPCFixupKinds.h"9#include "MCTargetDesc/PPCMCTargetDesc.h"10#include "llvm/BinaryFormat/ELF.h"11#include "llvm/BinaryFormat/MachO.h"12#include "llvm/MC/MCAsmBackend.h"13#include "llvm/MC/MCAssembler.h"14#include "llvm/MC/MCELFObjectWriter.h"15#include "llvm/MC/MCFixupKindInfo.h"16#include "llvm/MC/MCMachObjectWriter.h"17#include "llvm/MC/MCObjectWriter.h"18#include "llvm/MC/MCSectionMachO.h"19#include "llvm/MC/MCSubtargetInfo.h"20#include "llvm/MC/MCSymbolELF.h"21#include "llvm/MC/MCSymbolXCOFF.h"22#include "llvm/MC/MCValue.h"23#include "llvm/MC/TargetRegistry.h"24#include "llvm/Support/ErrorHandling.h"25using namespace llvm;2627static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {28switch (Kind) {29default:30llvm_unreachable("Unknown fixup kind!");31case FK_Data_1:32case FK_Data_2:33case FK_Data_4:34case FK_Data_8:35case PPC::fixup_ppc_nofixup:36return Value;37case PPC::fixup_ppc_brcond14:38case PPC::fixup_ppc_brcond14abs:39return Value & 0xfffc;40case PPC::fixup_ppc_br24:41case PPC::fixup_ppc_br24abs:42case PPC::fixup_ppc_br24_notoc:43return Value & 0x3fffffc;44case PPC::fixup_ppc_half16:45return Value & 0xffff;46case PPC::fixup_ppc_half16ds:47case PPC::fixup_ppc_half16dq:48return Value & 0xfffc;49case PPC::fixup_ppc_pcrel34:50case PPC::fixup_ppc_imm34:51return Value & 0x3ffffffff;52}53}5455static unsigned getFixupKindNumBytes(unsigned Kind) {56switch (Kind) {57default:58llvm_unreachable("Unknown fixup kind!");59case FK_Data_1:60return 1;61case FK_Data_2:62case PPC::fixup_ppc_half16:63case PPC::fixup_ppc_half16ds:64case PPC::fixup_ppc_half16dq:65return 2;66case FK_Data_4:67case PPC::fixup_ppc_brcond14:68case PPC::fixup_ppc_brcond14abs:69case PPC::fixup_ppc_br24:70case PPC::fixup_ppc_br24abs:71case PPC::fixup_ppc_br24_notoc:72return 4;73case PPC::fixup_ppc_pcrel34:74case PPC::fixup_ppc_imm34:75case FK_Data_8:76return 8;77case PPC::fixup_ppc_nofixup:78return 0;79}80}8182namespace {8384class PPCAsmBackend : public MCAsmBackend {85protected:86Triple TT;87public:88PPCAsmBackend(const Target &T, const Triple &TT)89: MCAsmBackend(TT.isLittleEndian() ? llvm::endianness::little90: llvm::endianness::big),91TT(TT) {}9293unsigned getNumFixupKinds() const override {94return PPC::NumTargetFixupKinds;95}9697const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override {98const static MCFixupKindInfo InfosBE[PPC::NumTargetFixupKinds] = {99// name offset bits flags100{ "fixup_ppc_br24", 6, 24, MCFixupKindInfo::FKF_IsPCRel },101{ "fixup_ppc_br24_notoc", 6, 24, MCFixupKindInfo::FKF_IsPCRel },102{ "fixup_ppc_brcond14", 16, 14, MCFixupKindInfo::FKF_IsPCRel },103{ "fixup_ppc_br24abs", 6, 24, 0 },104{ "fixup_ppc_brcond14abs", 16, 14, 0 },105{ "fixup_ppc_half16", 0, 16, 0 },106{ "fixup_ppc_half16ds", 0, 14, 0 },107{ "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel },108{ "fixup_ppc_imm34", 0, 34, 0 },109{ "fixup_ppc_nofixup", 0, 0, 0 }110};111const static MCFixupKindInfo InfosLE[PPC::NumTargetFixupKinds] = {112// name offset bits flags113{ "fixup_ppc_br24", 2, 24, MCFixupKindInfo::FKF_IsPCRel },114{ "fixup_ppc_br24_notoc", 2, 24, MCFixupKindInfo::FKF_IsPCRel },115{ "fixup_ppc_brcond14", 2, 14, MCFixupKindInfo::FKF_IsPCRel },116{ "fixup_ppc_br24abs", 2, 24, 0 },117{ "fixup_ppc_brcond14abs", 2, 14, 0 },118{ "fixup_ppc_half16", 0, 16, 0 },119{ "fixup_ppc_half16ds", 2, 14, 0 },120{ "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel },121{ "fixup_ppc_imm34", 0, 34, 0 },122{ "fixup_ppc_nofixup", 0, 0, 0 }123};124125// Fixup kinds from .reloc directive are like R_PPC_NONE/R_PPC64_NONE. They126// do not require any extra processing.127if (Kind >= FirstLiteralRelocationKind)128return MCAsmBackend::getFixupKindInfo(FK_NONE);129130if (Kind < FirstTargetFixupKind)131return MCAsmBackend::getFixupKindInfo(Kind);132133assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&134"Invalid kind!");135return (Endian == llvm::endianness::little136? InfosLE137: InfosBE)[Kind - FirstTargetFixupKind];138}139140void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,141const MCValue &Target, MutableArrayRef<char> Data,142uint64_t Value, bool IsResolved,143const MCSubtargetInfo *STI) const override {144MCFixupKind Kind = Fixup.getKind();145if (Kind >= FirstLiteralRelocationKind)146return;147Value = adjustFixupValue(Kind, Value);148if (!Value) return; // Doesn't change encoding.149150unsigned Offset = Fixup.getOffset();151unsigned NumBytes = getFixupKindNumBytes(Kind);152153// For each byte of the fragment that the fixup touches, mask in the bits154// from the fixup value. The Value has been "split up" into the appropriate155// bitfields above.156for (unsigned i = 0; i != NumBytes; ++i) {157unsigned Idx =158Endian == llvm::endianness::little ? i : (NumBytes - 1 - i);159Data[Offset + i] |= uint8_t((Value >> (Idx * 8)) & 0xff);160}161}162163bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,164const MCValue &Target,165const MCSubtargetInfo *STI) override {166MCFixupKind Kind = Fixup.getKind();167switch ((unsigned)Kind) {168default:169return Kind >= FirstLiteralRelocationKind;170case PPC::fixup_ppc_br24:171case PPC::fixup_ppc_br24abs:172case PPC::fixup_ppc_br24_notoc:173// If the target symbol has a local entry point we must not attempt174// to resolve the fixup directly. Emit a relocation and leave175// resolution of the final target address to the linker.176if (const MCSymbolRefExpr *A = Target.getSymA()) {177if (const auto *S = dyn_cast<MCSymbolELF>(&A->getSymbol())) {178// The "other" values are stored in the last 6 bits of the second179// byte. The traditional defines for STO values assume the full byte180// and thus the shift to pack it.181unsigned Other = S->getOther() << 2;182if ((Other & ELF::STO_PPC64_LOCAL_MASK) != 0)183return true;184} else if (const auto *S = dyn_cast<MCSymbolXCOFF>(&A->getSymbol())) {185return !Target.isAbsolute() && S->isExternal() &&186S->getStorageClass() == XCOFF::C_WEAKEXT;187}188}189return false;190}191}192193void relaxInstruction(MCInst &Inst,194const MCSubtargetInfo &STI) const override {195// FIXME.196llvm_unreachable("relaxInstruction() unimplemented");197}198199bool writeNopData(raw_ostream &OS, uint64_t Count,200const MCSubtargetInfo *STI) const override {201uint64_t NumNops = Count / 4;202for (uint64_t i = 0; i != NumNops; ++i)203support::endian::write<uint32_t>(OS, 0x60000000, Endian);204205OS.write_zeros(Count % 4);206207return true;208}209};210} // end anonymous namespace211212213// FIXME: This should be in a separate file.214namespace {215216class ELFPPCAsmBackend : public PPCAsmBackend {217public:218ELFPPCAsmBackend(const Target &T, const Triple &TT) : PPCAsmBackend(T, TT) {}219220std::unique_ptr<MCObjectTargetWriter>221createObjectTargetWriter() const override {222uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());223bool Is64 = TT.isPPC64();224return createPPCELFObjectWriter(Is64, OSABI);225}226227std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;228};229230class XCOFFPPCAsmBackend : public PPCAsmBackend {231public:232XCOFFPPCAsmBackend(const Target &T, const Triple &TT)233: PPCAsmBackend(T, TT) {}234235std::unique_ptr<MCObjectTargetWriter>236createObjectTargetWriter() const override {237return createPPCXCOFFObjectWriter(TT.isArch64Bit());238}239240std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;241};242243} // end anonymous namespace244245std::optional<MCFixupKind>246ELFPPCAsmBackend::getFixupKind(StringRef Name) const {247if (TT.isOSBinFormatELF()) {248unsigned Type;249if (TT.isPPC64()) {250Type = llvm::StringSwitch<unsigned>(Name)251#define ELF_RELOC(X, Y) .Case(#X, Y)252#include "llvm/BinaryFormat/ELFRelocs/PowerPC64.def"253#undef ELF_RELOC254.Case("BFD_RELOC_NONE", ELF::R_PPC64_NONE)255.Case("BFD_RELOC_16", ELF::R_PPC64_ADDR16)256.Case("BFD_RELOC_32", ELF::R_PPC64_ADDR32)257.Case("BFD_RELOC_64", ELF::R_PPC64_ADDR64)258.Default(-1u);259} else {260Type = llvm::StringSwitch<unsigned>(Name)261#define ELF_RELOC(X, Y) .Case(#X, Y)262#include "llvm/BinaryFormat/ELFRelocs/PowerPC.def"263#undef ELF_RELOC264.Case("BFD_RELOC_NONE", ELF::R_PPC_NONE)265.Case("BFD_RELOC_16", ELF::R_PPC_ADDR16)266.Case("BFD_RELOC_32", ELF::R_PPC_ADDR32)267.Default(-1u);268}269if (Type != -1u)270return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);271}272return std::nullopt;273}274275std::optional<MCFixupKind>276XCOFFPPCAsmBackend::getFixupKind(StringRef Name) const {277return StringSwitch<std::optional<MCFixupKind>>(Name)278.Case("R_REF", (MCFixupKind)PPC::fixup_ppc_nofixup)279.Default(std::nullopt);280}281282MCAsmBackend *llvm::createPPCAsmBackend(const Target &T,283const MCSubtargetInfo &STI,284const MCRegisterInfo &MRI,285const MCTargetOptions &Options) {286const Triple &TT = STI.getTargetTriple();287if (TT.isOSBinFormatXCOFF())288return new XCOFFPPCAsmBackend(T, TT);289290return new ELFPPCAsmBackend(T, TT);291}292293294