10b57cec5SDimitry Andric //===-- PPCAsmBackend.cpp - PPC 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/PPCFixupKinds.h"
100b57cec5SDimitry Andric #include "MCTargetDesc/PPCMCTargetDesc.h"
110b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
120b57cec5SDimitry Andric #include "llvm/BinaryFormat/MachO.h"
130b57cec5SDimitry Andric #include "llvm/MC/MCAsmBackend.h"
140b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h"
150b57cec5SDimitry Andric #include "llvm/MC/MCELFObjectWriter.h"
160b57cec5SDimitry Andric #include "llvm/MC/MCFixupKindInfo.h"
170b57cec5SDimitry Andric #include "llvm/MC/MCMachObjectWriter.h"
180b57cec5SDimitry Andric #include "llvm/MC/MCObjectWriter.h"
190b57cec5SDimitry Andric #include "llvm/MC/MCSectionMachO.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCSymbolELF.h"
2206c3fb27SDimitry Andric #include "llvm/MC/MCSymbolXCOFF.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCValue.h"
24349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
250b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
260b57cec5SDimitry Andric using namespace llvm;
270b57cec5SDimitry Andric
adjustFixupValue(unsigned Kind,uint64_t Value)280b57cec5SDimitry Andric static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
290b57cec5SDimitry Andric switch (Kind) {
300b57cec5SDimitry Andric default:
310b57cec5SDimitry Andric llvm_unreachable("Unknown fixup kind!");
320b57cec5SDimitry Andric case FK_Data_1:
330b57cec5SDimitry Andric case FK_Data_2:
340b57cec5SDimitry Andric case FK_Data_4:
350b57cec5SDimitry Andric case FK_Data_8:
360b57cec5SDimitry Andric case PPC::fixup_ppc_nofixup:
370b57cec5SDimitry Andric return Value;
380b57cec5SDimitry Andric case PPC::fixup_ppc_brcond14:
390b57cec5SDimitry Andric case PPC::fixup_ppc_brcond14abs:
400b57cec5SDimitry Andric return Value & 0xfffc;
410b57cec5SDimitry Andric case PPC::fixup_ppc_br24:
420b57cec5SDimitry Andric case PPC::fixup_ppc_br24abs:
435ffd83dbSDimitry Andric case PPC::fixup_ppc_br24_notoc:
440b57cec5SDimitry Andric return Value & 0x3fffffc;
450b57cec5SDimitry Andric case PPC::fixup_ppc_half16:
460b57cec5SDimitry Andric return Value & 0xffff;
470b57cec5SDimitry Andric case PPC::fixup_ppc_half16ds:
483a9a9c0cSDimitry Andric case PPC::fixup_ppc_half16dq:
490b57cec5SDimitry Andric return Value & 0xfffc;
505ffd83dbSDimitry Andric case PPC::fixup_ppc_pcrel34:
51e8d8bef9SDimitry Andric case PPC::fixup_ppc_imm34:
525ffd83dbSDimitry Andric return Value & 0x3ffffffff;
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric
getFixupKindNumBytes(unsigned Kind)560b57cec5SDimitry Andric static unsigned getFixupKindNumBytes(unsigned Kind) {
570b57cec5SDimitry Andric switch (Kind) {
580b57cec5SDimitry Andric default:
590b57cec5SDimitry Andric llvm_unreachable("Unknown fixup kind!");
600b57cec5SDimitry Andric case FK_Data_1:
610b57cec5SDimitry Andric return 1;
620b57cec5SDimitry Andric case FK_Data_2:
630b57cec5SDimitry Andric case PPC::fixup_ppc_half16:
640b57cec5SDimitry Andric case PPC::fixup_ppc_half16ds:
653a9a9c0cSDimitry Andric case PPC::fixup_ppc_half16dq:
660b57cec5SDimitry Andric return 2;
670b57cec5SDimitry Andric case FK_Data_4:
680b57cec5SDimitry Andric case PPC::fixup_ppc_brcond14:
690b57cec5SDimitry Andric case PPC::fixup_ppc_brcond14abs:
700b57cec5SDimitry Andric case PPC::fixup_ppc_br24:
710b57cec5SDimitry Andric case PPC::fixup_ppc_br24abs:
725ffd83dbSDimitry Andric case PPC::fixup_ppc_br24_notoc:
730b57cec5SDimitry Andric return 4;
745ffd83dbSDimitry Andric case PPC::fixup_ppc_pcrel34:
75e8d8bef9SDimitry Andric case PPC::fixup_ppc_imm34:
760b57cec5SDimitry Andric case FK_Data_8:
770b57cec5SDimitry Andric return 8;
780b57cec5SDimitry Andric case PPC::fixup_ppc_nofixup:
790b57cec5SDimitry Andric return 0;
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric
830b57cec5SDimitry Andric namespace {
840b57cec5SDimitry Andric
850b57cec5SDimitry Andric class PPCAsmBackend : public MCAsmBackend {
860b57cec5SDimitry Andric protected:
870b57cec5SDimitry Andric Triple TT;
880b57cec5SDimitry Andric public:
PPCAsmBackend(const Target & T,const Triple & TT)890b57cec5SDimitry Andric PPCAsmBackend(const Target &T, const Triple &TT)
90*5f757f3fSDimitry Andric : MCAsmBackend(TT.isLittleEndian() ? llvm::endianness::little
91*5f757f3fSDimitry Andric : llvm::endianness::big),
920b57cec5SDimitry Andric TT(TT) {}
930b57cec5SDimitry Andric
getNumFixupKinds() const940b57cec5SDimitry Andric unsigned getNumFixupKinds() const override {
950b57cec5SDimitry Andric return PPC::NumTargetFixupKinds;
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric
getFixupKindInfo(MCFixupKind Kind) const980b57cec5SDimitry Andric const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override {
990b57cec5SDimitry Andric const static MCFixupKindInfo InfosBE[PPC::NumTargetFixupKinds] = {
1000b57cec5SDimitry Andric // name offset bits flags
1010b57cec5SDimitry Andric { "fixup_ppc_br24", 6, 24, MCFixupKindInfo::FKF_IsPCRel },
1025ffd83dbSDimitry Andric { "fixup_ppc_br24_notoc", 6, 24, MCFixupKindInfo::FKF_IsPCRel },
1030b57cec5SDimitry Andric { "fixup_ppc_brcond14", 16, 14, MCFixupKindInfo::FKF_IsPCRel },
1040b57cec5SDimitry Andric { "fixup_ppc_br24abs", 6, 24, 0 },
1050b57cec5SDimitry Andric { "fixup_ppc_brcond14abs", 16, 14, 0 },
1060b57cec5SDimitry Andric { "fixup_ppc_half16", 0, 16, 0 },
1070b57cec5SDimitry Andric { "fixup_ppc_half16ds", 0, 14, 0 },
1085ffd83dbSDimitry Andric { "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel },
109e8d8bef9SDimitry Andric { "fixup_ppc_imm34", 0, 34, 0 },
1100b57cec5SDimitry Andric { "fixup_ppc_nofixup", 0, 0, 0 }
1110b57cec5SDimitry Andric };
1120b57cec5SDimitry Andric const static MCFixupKindInfo InfosLE[PPC::NumTargetFixupKinds] = {
1130b57cec5SDimitry Andric // name offset bits flags
1140b57cec5SDimitry Andric { "fixup_ppc_br24", 2, 24, MCFixupKindInfo::FKF_IsPCRel },
1155ffd83dbSDimitry Andric { "fixup_ppc_br24_notoc", 2, 24, MCFixupKindInfo::FKF_IsPCRel },
1160b57cec5SDimitry Andric { "fixup_ppc_brcond14", 2, 14, MCFixupKindInfo::FKF_IsPCRel },
1170b57cec5SDimitry Andric { "fixup_ppc_br24abs", 2, 24, 0 },
1180b57cec5SDimitry Andric { "fixup_ppc_brcond14abs", 2, 14, 0 },
1190b57cec5SDimitry Andric { "fixup_ppc_half16", 0, 16, 0 },
1200b57cec5SDimitry Andric { "fixup_ppc_half16ds", 2, 14, 0 },
1215ffd83dbSDimitry Andric { "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel },
122e8d8bef9SDimitry Andric { "fixup_ppc_imm34", 0, 34, 0 },
1230b57cec5SDimitry Andric { "fixup_ppc_nofixup", 0, 0, 0 }
1240b57cec5SDimitry Andric };
1250b57cec5SDimitry Andric
1265ffd83dbSDimitry Andric // Fixup kinds from .reloc directive are like R_PPC_NONE/R_PPC64_NONE. They
1275ffd83dbSDimitry Andric // do not require any extra processing.
1285ffd83dbSDimitry Andric if (Kind >= FirstLiteralRelocationKind)
1295ffd83dbSDimitry Andric return MCAsmBackend::getFixupKindInfo(FK_NONE);
1305ffd83dbSDimitry Andric
1310b57cec5SDimitry Andric if (Kind < FirstTargetFixupKind)
1320b57cec5SDimitry Andric return MCAsmBackend::getFixupKindInfo(Kind);
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
1350b57cec5SDimitry Andric "Invalid kind!");
136*5f757f3fSDimitry Andric return (Endian == llvm::endianness::little
1370b57cec5SDimitry Andric ? InfosLE
1380b57cec5SDimitry Andric : InfosBE)[Kind - FirstTargetFixupKind];
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric
applyFixup(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool IsResolved,const MCSubtargetInfo * STI) const1410b57cec5SDimitry Andric void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
1420b57cec5SDimitry Andric const MCValue &Target, MutableArrayRef<char> Data,
1430b57cec5SDimitry Andric uint64_t Value, bool IsResolved,
1440b57cec5SDimitry Andric const MCSubtargetInfo *STI) const override {
1455ffd83dbSDimitry Andric MCFixupKind Kind = Fixup.getKind();
1465ffd83dbSDimitry Andric if (Kind >= FirstLiteralRelocationKind)
1475ffd83dbSDimitry Andric return;
1485ffd83dbSDimitry Andric Value = adjustFixupValue(Kind, Value);
1490b57cec5SDimitry Andric if (!Value) return; // Doesn't change encoding.
1500b57cec5SDimitry Andric
1510b57cec5SDimitry Andric unsigned Offset = Fixup.getOffset();
1525ffd83dbSDimitry Andric unsigned NumBytes = getFixupKindNumBytes(Kind);
1530b57cec5SDimitry Andric
1540b57cec5SDimitry Andric // For each byte of the fragment that the fixup touches, mask in the bits
1550b57cec5SDimitry Andric // from the fixup value. The Value has been "split up" into the appropriate
1560b57cec5SDimitry Andric // bitfields above.
1570b57cec5SDimitry Andric for (unsigned i = 0; i != NumBytes; ++i) {
158*5f757f3fSDimitry Andric unsigned Idx =
159*5f757f3fSDimitry Andric Endian == llvm::endianness::little ? i : (NumBytes - 1 - i);
1600b57cec5SDimitry Andric Data[Offset + i] |= uint8_t((Value >> (Idx * 8)) & 0xff);
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric
shouldForceRelocation(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,const MCSubtargetInfo * STI)1640b57cec5SDimitry Andric bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,
165*5f757f3fSDimitry Andric const MCValue &Target,
166*5f757f3fSDimitry Andric const MCSubtargetInfo *STI) override {
1675ffd83dbSDimitry Andric MCFixupKind Kind = Fixup.getKind();
1685ffd83dbSDimitry Andric switch ((unsigned)Kind) {
1690b57cec5SDimitry Andric default:
1705ffd83dbSDimitry Andric return Kind >= FirstLiteralRelocationKind;
1710b57cec5SDimitry Andric case PPC::fixup_ppc_br24:
1720b57cec5SDimitry Andric case PPC::fixup_ppc_br24abs:
1735ffd83dbSDimitry Andric case PPC::fixup_ppc_br24_notoc:
1740b57cec5SDimitry Andric // If the target symbol has a local entry point we must not attempt
1750b57cec5SDimitry Andric // to resolve the fixup directly. Emit a relocation and leave
1760b57cec5SDimitry Andric // resolution of the final target address to the linker.
1770b57cec5SDimitry Andric if (const MCSymbolRefExpr *A = Target.getSymA()) {
1780b57cec5SDimitry Andric if (const auto *S = dyn_cast<MCSymbolELF>(&A->getSymbol())) {
1790b57cec5SDimitry Andric // The "other" values are stored in the last 6 bits of the second
1800b57cec5SDimitry Andric // byte. The traditional defines for STO values assume the full byte
1810b57cec5SDimitry Andric // and thus the shift to pack it.
1820b57cec5SDimitry Andric unsigned Other = S->getOther() << 2;
1830b57cec5SDimitry Andric if ((Other & ELF::STO_PPC64_LOCAL_MASK) != 0)
1840b57cec5SDimitry Andric return true;
18506c3fb27SDimitry Andric } else if (const auto *S = dyn_cast<MCSymbolXCOFF>(&A->getSymbol())) {
18606c3fb27SDimitry Andric return !Target.isAbsolute() && S->isExternal() &&
18706c3fb27SDimitry Andric S->getStorageClass() == XCOFF::C_WEAKEXT;
1880b57cec5SDimitry Andric }
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric return false;
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric
relaxInstruction(MCInst & Inst,const MCSubtargetInfo & STI) const1945ffd83dbSDimitry Andric void relaxInstruction(MCInst &Inst,
1955ffd83dbSDimitry Andric const MCSubtargetInfo &STI) const override {
1960b57cec5SDimitry Andric // FIXME.
1970b57cec5SDimitry Andric llvm_unreachable("relaxInstruction() unimplemented");
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric
writeNopData(raw_ostream & OS,uint64_t Count,const MCSubtargetInfo * STI) const200349cc55cSDimitry Andric bool writeNopData(raw_ostream &OS, uint64_t Count,
201349cc55cSDimitry Andric const MCSubtargetInfo *STI) const override {
2020b57cec5SDimitry Andric uint64_t NumNops = Count / 4;
2030b57cec5SDimitry Andric for (uint64_t i = 0; i != NumNops; ++i)
2040b57cec5SDimitry Andric support::endian::write<uint32_t>(OS, 0x60000000, Endian);
2050b57cec5SDimitry Andric
2060b57cec5SDimitry Andric OS.write_zeros(Count % 4);
2070b57cec5SDimitry Andric
2080b57cec5SDimitry Andric return true;
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric };
2110b57cec5SDimitry Andric } // end anonymous namespace
2120b57cec5SDimitry Andric
2130b57cec5SDimitry Andric
2140b57cec5SDimitry Andric // FIXME: This should be in a separate file.
2150b57cec5SDimitry Andric namespace {
2160b57cec5SDimitry Andric
2170b57cec5SDimitry Andric class ELFPPCAsmBackend : public PPCAsmBackend {
2180b57cec5SDimitry Andric public:
ELFPPCAsmBackend(const Target & T,const Triple & TT)2190b57cec5SDimitry Andric ELFPPCAsmBackend(const Target &T, const Triple &TT) : PPCAsmBackend(T, TT) {}
2200b57cec5SDimitry Andric
2210b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const2220b57cec5SDimitry Andric createObjectTargetWriter() const override {
2230b57cec5SDimitry Andric uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());
2240b57cec5SDimitry Andric bool Is64 = TT.isPPC64();
2250b57cec5SDimitry Andric return createPPCELFObjectWriter(Is64, OSABI);
2260b57cec5SDimitry Andric }
2270b57cec5SDimitry Andric
228bdd1243dSDimitry Andric std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
2290b57cec5SDimitry Andric };
2300b57cec5SDimitry Andric
2310b57cec5SDimitry Andric class XCOFFPPCAsmBackend : public PPCAsmBackend {
2320b57cec5SDimitry Andric public:
XCOFFPPCAsmBackend(const Target & T,const Triple & TT)2330b57cec5SDimitry Andric XCOFFPPCAsmBackend(const Target &T, const Triple &TT)
2340b57cec5SDimitry Andric : PPCAsmBackend(T, TT) {}
2350b57cec5SDimitry Andric
2360b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const2370b57cec5SDimitry Andric createObjectTargetWriter() const override {
2380b57cec5SDimitry Andric return createPPCXCOFFObjectWriter(TT.isArch64Bit());
2390b57cec5SDimitry Andric }
24006c3fb27SDimitry Andric
24106c3fb27SDimitry Andric std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
2420b57cec5SDimitry Andric };
2430b57cec5SDimitry Andric
2440b57cec5SDimitry Andric } // end anonymous namespace
2450b57cec5SDimitry Andric
246bdd1243dSDimitry Andric std::optional<MCFixupKind>
getFixupKind(StringRef Name) const247bdd1243dSDimitry Andric ELFPPCAsmBackend::getFixupKind(StringRef Name) const {
2485ffd83dbSDimitry Andric if (TT.isOSBinFormatELF()) {
2495ffd83dbSDimitry Andric unsigned Type;
2500b57cec5SDimitry Andric if (TT.isPPC64()) {
2515ffd83dbSDimitry Andric Type = llvm::StringSwitch<unsigned>(Name)
2525ffd83dbSDimitry Andric #define ELF_RELOC(X, Y) .Case(#X, Y)
2535ffd83dbSDimitry Andric #include "llvm/BinaryFormat/ELFRelocs/PowerPC64.def"
2545ffd83dbSDimitry Andric #undef ELF_RELOC
255fe6060f1SDimitry Andric .Case("BFD_RELOC_NONE", ELF::R_PPC64_NONE)
256fe6060f1SDimitry Andric .Case("BFD_RELOC_16", ELF::R_PPC64_ADDR16)
257fe6060f1SDimitry Andric .Case("BFD_RELOC_32", ELF::R_PPC64_ADDR32)
258fe6060f1SDimitry Andric .Case("BFD_RELOC_64", ELF::R_PPC64_ADDR64)
2595ffd83dbSDimitry Andric .Default(-1u);
2600b57cec5SDimitry Andric } else {
2615ffd83dbSDimitry Andric Type = llvm::StringSwitch<unsigned>(Name)
2625ffd83dbSDimitry Andric #define ELF_RELOC(X, Y) .Case(#X, Y)
2635ffd83dbSDimitry Andric #include "llvm/BinaryFormat/ELFRelocs/PowerPC.def"
2645ffd83dbSDimitry Andric #undef ELF_RELOC
265fe6060f1SDimitry Andric .Case("BFD_RELOC_NONE", ELF::R_PPC_NONE)
266fe6060f1SDimitry Andric .Case("BFD_RELOC_16", ELF::R_PPC_ADDR16)
267fe6060f1SDimitry Andric .Case("BFD_RELOC_32", ELF::R_PPC_ADDR32)
2685ffd83dbSDimitry Andric .Default(-1u);
2690b57cec5SDimitry Andric }
2705ffd83dbSDimitry Andric if (Type != -1u)
2715ffd83dbSDimitry Andric return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);
2725ffd83dbSDimitry Andric }
273bdd1243dSDimitry Andric return std::nullopt;
2740b57cec5SDimitry Andric }
2750b57cec5SDimitry Andric
27606c3fb27SDimitry Andric std::optional<MCFixupKind>
getFixupKind(StringRef Name) const27706c3fb27SDimitry Andric XCOFFPPCAsmBackend::getFixupKind(StringRef Name) const {
27806c3fb27SDimitry Andric return StringSwitch<std::optional<MCFixupKind>>(Name)
27906c3fb27SDimitry Andric .Case("R_REF", (MCFixupKind)PPC::fixup_ppc_nofixup)
28006c3fb27SDimitry Andric .Default(std::nullopt);
28106c3fb27SDimitry Andric }
28206c3fb27SDimitry Andric
createPPCAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions & Options)2830b57cec5SDimitry Andric MCAsmBackend *llvm::createPPCAsmBackend(const Target &T,
2840b57cec5SDimitry Andric const MCSubtargetInfo &STI,
2850b57cec5SDimitry Andric const MCRegisterInfo &MRI,
2860b57cec5SDimitry Andric const MCTargetOptions &Options) {
2870b57cec5SDimitry Andric const Triple &TT = STI.getTargetTriple();
2880b57cec5SDimitry Andric if (TT.isOSBinFormatXCOFF())
2890b57cec5SDimitry Andric return new XCOFFPPCAsmBackend(T, TT);
2900b57cec5SDimitry Andric
2910b57cec5SDimitry Andric return new ELFPPCAsmBackend(T, TT);
2920b57cec5SDimitry Andric }
293