//===-- BPFAsmPrinter.cpp - BPF LLVM assembly writer ----------------------===// // // 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 // //===----------------------------------------------------------------------===// // // This file contains a printer that converts from our internal representation // of machine-dependent LLVM code to the BPF assembly language. // //===----------------------------------------------------------------------===// #include "BPFAsmPrinter.h" #include "BPF.h" #include "BPFInstrInfo.h" #include "BPFMCInstLower.h" #include "BTFDebug.h" #include "MCTargetDesc/BPFInstPrinter.h" #include "TargetInfo/BPFTargetInfo.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolELF.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetLoweringObjectFile.h" using namespace llvm; #define DEBUG_TYPE "asm-printer" bool BPFAsmPrinter::doInitialization(Module &M) { AsmPrinter::doInitialization(M); // Only emit BTF when debuginfo available. if (MAI->doesSupportDebugInformation() && !M.debug_compile_units().empty()) { BTF = new BTFDebug(this); Handlers.push_back(std::unique_ptr(BTF)); } return false; } const BPFTargetMachine &BPFAsmPrinter::getBTM() const { return static_cast(TM); } bool BPFAsmPrinter::doFinalization(Module &M) { // Remove unused globals which are previously used for jump table. const BPFSubtarget *Subtarget = getBTM().getSubtargetImpl(); if (Subtarget->hasGotox()) { std::vector Targets; for (GlobalVariable &Global : M.globals()) { if (Global.getLinkage() != GlobalValue::PrivateLinkage) continue; if (!Global.isConstant() || !Global.hasInitializer()) continue; Constant *CV = dyn_cast(Global.getInitializer()); if (!CV) continue; ConstantArray *CA = dyn_cast(CV); if (!CA) continue; for (unsigned i = 1, e = CA->getNumOperands(); i != e; ++i) { if (!dyn_cast(CA->getOperand(i))) continue; } Targets.push_back(&Global); } for (GlobalVariable *GV : Targets) { GV->replaceAllUsesWith(PoisonValue::get(GV->getType())); GV->dropAllReferences(); GV->eraseFromParent(); } } return AsmPrinter::doFinalization(M); } void BPFAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O) { const MachineOperand &MO = MI->getOperand(OpNum); switch (MO.getType()) { case MachineOperand::MO_Register: O << BPFInstPrinter::getRegisterName(MO.getReg()); break; case MachineOperand::MO_Immediate: O << MO.getImm(); break; case MachineOperand::MO_MachineBasicBlock: O << *MO.getMBB()->getSymbol(); break; case MachineOperand::MO_GlobalAddress: O << *getSymbol(MO.getGlobal()); break; case MachineOperand::MO_BlockAddress: { MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress()); O << BA->getName(); break; } case MachineOperand::MO_ExternalSymbol: O << *GetExternalSymbolSymbol(MO.getSymbolName()); break; case MachineOperand::MO_JumpTableIndex: case MachineOperand::MO_ConstantPoolIndex: default: llvm_unreachable(""); } } bool BPFAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &O) { if (ExtraCode && ExtraCode[0]) return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O); printOperand(MI, OpNo, O); return false; } bool BPFAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, const char *ExtraCode, raw_ostream &O) { assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands"); const MachineOperand &BaseMO = MI->getOperand(OpNum); const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1); assert(BaseMO.isReg() && "Unexpected base pointer for inline asm memory operand."); assert(OffsetMO.isImm() && "Unexpected offset for inline asm memory operand."); int Offset = OffsetMO.getImm(); if (ExtraCode) return true; // Unknown modifier. if (Offset < 0) O << "(" << BPFInstPrinter::getRegisterName(BaseMO.getReg()) << " - " << -Offset << ")"; else O << "(" << BPFInstPrinter::getRegisterName(BaseMO.getReg()) << " + " << Offset << ")"; return false; } void BPFAsmPrinter::emitInstruction(const MachineInstr *MI) { BPF_MC::verifyInstructionPredicates(MI->getOpcode(), getSubtargetInfo().getFeatureBits()); MCInst TmpInst; if (!BTF || !BTF->InstLower(MI, TmpInst)) { BPFMCInstLower MCInstLowering(OutContext, *this); MCInstLowering.Lower(MI, TmpInst); } EmitToStreamer(*OutStreamer, TmpInst); } MCSymbol *BPFAsmPrinter::getJTPublicSymbol(unsigned JTI) { SmallString<60> Name; raw_svector_ostream(Name) << "BPF.JT." << MF->getFunctionNumber() << '.' << JTI; MCSymbol *S = OutContext.getOrCreateSymbol(Name); if (auto *ES = static_cast(S)) { ES->setBinding(ELF::STB_GLOBAL); ES->setType(ELF::STT_OBJECT); } return S; } void BPFAsmPrinter::emitJumpTableInfo() { const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); if (!MJTI) return; const std::vector &JT = MJTI->getJumpTables(); if (JT.empty()) return; const TargetLoweringObjectFile &TLOF = getObjFileLowering(); const Function &F = MF->getFunction(); MCSection *JTS = TLOF.getSectionForJumpTable(F, TM); assert(MJTI->getEntryKind() == MachineJumpTableInfo::EK_BlockAddress); unsigned EntrySize = MJTI->getEntrySize(getDataLayout()); OutStreamer->switchSection(JTS); for (unsigned JTI = 0; JTI < JT.size(); JTI++) { ArrayRef JTBBs = JT[JTI].MBBs; if (JTBBs.empty()) continue; MCSymbol *JTStart = getJTPublicSymbol(JTI); OutStreamer->emitLabel(JTStart); for (const MachineBasicBlock *MBB : JTBBs) { const MCExpr *LHS = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext); OutStreamer->emitValue(LHS, EntrySize); } const MCExpr *JTSize = MCConstantExpr::create(JTBBs.size() * EntrySize, OutContext); OutStreamer->emitELFSize(JTStart, JTSize); } } char BPFAsmPrinter::ID = 0; INITIALIZE_PASS(BPFAsmPrinter, "bpf-asm-printer", "BPF Assembly Printer", false, false) // Force static initialization. extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFAsmPrinter() { RegisterAsmPrinter X(getTheBPFleTarget()); RegisterAsmPrinter Y(getTheBPFbeTarget()); RegisterAsmPrinter Z(getTheBPFTarget()); }