257 lines · cpp
1//===-- BPFAsmPrinter.cpp - BPF LLVM assembly writer ----------------------===//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// This file contains a printer that converts from our internal representation10// of machine-dependent LLVM code to the BPF assembly language.11//12//===----------------------------------------------------------------------===//13 14#include "BPFAsmPrinter.h"15#include "BPF.h"16#include "BPFInstrInfo.h"17#include "BPFMCInstLower.h"18#include "BTFDebug.h"19#include "MCTargetDesc/BPFInstPrinter.h"20#include "TargetInfo/BPFTargetInfo.h"21#include "llvm/BinaryFormat/ELF.h"22#include "llvm/CodeGen/AsmPrinter.h"23#include "llvm/CodeGen/MachineConstantPool.h"24#include "llvm/CodeGen/MachineInstr.h"25#include "llvm/CodeGen/MachineJumpTableInfo.h"26#include "llvm/CodeGen/MachineModuleInfo.h"27#include "llvm/CodeGen/TargetLowering.h"28#include "llvm/IR/Module.h"29#include "llvm/MC/MCAsmInfo.h"30#include "llvm/MC/MCExpr.h"31#include "llvm/MC/MCInst.h"32#include "llvm/MC/MCStreamer.h"33#include "llvm/MC/MCSymbol.h"34#include "llvm/MC/MCSymbolELF.h"35#include "llvm/MC/TargetRegistry.h"36#include "llvm/Support/Compiler.h"37#include "llvm/Support/raw_ostream.h"38#include "llvm/Target/TargetLoweringObjectFile.h"39using namespace llvm;40 41#define DEBUG_TYPE "asm-printer"42 43bool BPFAsmPrinter::doInitialization(Module &M) {44 AsmPrinter::doInitialization(M);45 46 // Only emit BTF when debuginfo available.47 if (MAI->doesSupportDebugInformation() && !M.debug_compile_units().empty()) {48 BTF = new BTFDebug(this);49 Handlers.push_back(std::unique_ptr<BTFDebug>(BTF));50 }51 52 return false;53}54 55const BPFTargetMachine &BPFAsmPrinter::getBTM() const {56 return static_cast<const BPFTargetMachine &>(TM);57}58 59bool BPFAsmPrinter::doFinalization(Module &M) {60 // Remove unused globals which are previously used for jump table.61 const BPFSubtarget *Subtarget = getBTM().getSubtargetImpl();62 if (Subtarget->hasGotox()) {63 std::vector<GlobalVariable *> Targets;64 for (GlobalVariable &Global : M.globals()) {65 if (Global.getLinkage() != GlobalValue::PrivateLinkage)66 continue;67 if (!Global.isConstant() || !Global.hasInitializer())68 continue;69 70 Constant *CV = dyn_cast<Constant>(Global.getInitializer());71 if (!CV)72 continue;73 ConstantArray *CA = dyn_cast<ConstantArray>(CV);74 if (!CA)75 continue;76 77 for (unsigned i = 1, e = CA->getNumOperands(); i != e; ++i) {78 if (!dyn_cast<BlockAddress>(CA->getOperand(i)))79 continue;80 }81 Targets.push_back(&Global);82 }83 84 for (GlobalVariable *GV : Targets) {85 GV->replaceAllUsesWith(PoisonValue::get(GV->getType()));86 GV->dropAllReferences();87 GV->eraseFromParent();88 }89 }90 91 for (GlobalObject &GO : M.global_objects()) {92 if (!GO.hasExternalWeakLinkage())93 continue;94 95 if (!SawTrapCall && GO.getName() == BPF_TRAP) {96 GO.eraseFromParent();97 break;98 }99 }100 101 return AsmPrinter::doFinalization(M);102}103 104void BPFAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,105 raw_ostream &O) {106 const MachineOperand &MO = MI->getOperand(OpNum);107 108 switch (MO.getType()) {109 case MachineOperand::MO_Register:110 O << BPFInstPrinter::getRegisterName(MO.getReg());111 break;112 113 case MachineOperand::MO_Immediate:114 O << MO.getImm();115 break;116 117 case MachineOperand::MO_MachineBasicBlock:118 O << *MO.getMBB()->getSymbol();119 break;120 121 case MachineOperand::MO_GlobalAddress:122 O << *getSymbol(MO.getGlobal());123 break;124 125 case MachineOperand::MO_BlockAddress: {126 MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());127 O << BA->getName();128 break;129 }130 131 case MachineOperand::MO_ExternalSymbol:132 O << *GetExternalSymbolSymbol(MO.getSymbolName());133 break;134 135 case MachineOperand::MO_JumpTableIndex:136 case MachineOperand::MO_ConstantPoolIndex:137 default:138 llvm_unreachable("<unknown operand type>");139 }140}141 142bool BPFAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,143 const char *ExtraCode, raw_ostream &O) {144 if (ExtraCode && ExtraCode[0])145 return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);146 147 printOperand(MI, OpNo, O);148 return false;149}150 151bool BPFAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,152 unsigned OpNum, const char *ExtraCode,153 raw_ostream &O) {154 assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands");155 const MachineOperand &BaseMO = MI->getOperand(OpNum);156 const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1);157 assert(BaseMO.isReg() && "Unexpected base pointer for inline asm memory operand.");158 assert(OffsetMO.isImm() && "Unexpected offset for inline asm memory operand.");159 int Offset = OffsetMO.getImm();160 161 if (ExtraCode)162 return true; // Unknown modifier.163 164 if (Offset < 0)165 O << "(" << BPFInstPrinter::getRegisterName(BaseMO.getReg()) << " - " << -Offset << ")";166 else167 O << "(" << BPFInstPrinter::getRegisterName(BaseMO.getReg()) << " + " << Offset << ")";168 169 return false;170}171 172void BPFAsmPrinter::emitInstruction(const MachineInstr *MI) {173 if (MI->isCall()) {174 for (const MachineOperand &Op : MI->operands()) {175 if (Op.isGlobal()) {176 if (const GlobalValue *GV = Op.getGlobal())177 if (GV->getName() == BPF_TRAP)178 SawTrapCall = true;179 }180 }181 }182 183 BPF_MC::verifyInstructionPredicates(MI->getOpcode(),184 getSubtargetInfo().getFeatureBits());185 186 MCInst TmpInst;187 188 if (!BTF || !BTF->InstLower(MI, TmpInst)) {189 BPFMCInstLower MCInstLowering(OutContext, *this);190 MCInstLowering.Lower(MI, TmpInst);191 }192 EmitToStreamer(*OutStreamer, TmpInst);193}194 195MCSymbol *BPFAsmPrinter::getJTPublicSymbol(unsigned JTI) {196 SmallString<60> Name;197 raw_svector_ostream(Name)198 << "BPF.JT." << MF->getFunctionNumber() << '.' << JTI;199 MCSymbol *S = OutContext.getOrCreateSymbol(Name);200 if (auto *ES = static_cast<MCSymbolELF *>(S)) {201 ES->setBinding(ELF::STB_GLOBAL);202 ES->setType(ELF::STT_OBJECT);203 }204 return S;205}206 207void BPFAsmPrinter::emitJumpTableInfo() {208 const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();209 if (!MJTI)210 return;211 212 const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();213 if (JT.empty())214 return;215 216 const TargetLoweringObjectFile &TLOF = getObjFileLowering();217 const Function &F = MF->getFunction();218 219 MCSection *Sec = OutStreamer->getCurrentSectionOnly();220 MCSymbol *SecStart = Sec->getBeginSymbol();221 222 MCSection *JTS = TLOF.getSectionForJumpTable(F, TM);223 assert(MJTI->getEntryKind() == MachineJumpTableInfo::EK_BlockAddress);224 unsigned EntrySize = MJTI->getEntrySize(getDataLayout());225 OutStreamer->switchSection(JTS);226 for (unsigned JTI = 0; JTI < JT.size(); JTI++) {227 ArrayRef<MachineBasicBlock *> JTBBs = JT[JTI].MBBs;228 if (JTBBs.empty())229 continue;230 231 MCSymbol *JTStart = getJTPublicSymbol(JTI);232 OutStreamer->emitLabel(JTStart);233 for (const MachineBasicBlock *MBB : JTBBs) {234 const MCExpr *Diff = MCBinaryExpr::createSub(235 MCSymbolRefExpr::create(MBB->getSymbol(), OutContext),236 MCSymbolRefExpr::create(SecStart, OutContext), OutContext);237 OutStreamer->emitValue(Diff, EntrySize);238 }239 const MCExpr *JTSize =240 MCConstantExpr::create(JTBBs.size() * EntrySize, OutContext);241 OutStreamer->emitELFSize(JTStart, JTSize);242 }243}244 245char BPFAsmPrinter::ID = 0;246 247INITIALIZE_PASS(BPFAsmPrinter, "bpf-asm-printer", "BPF Assembly Printer", false,248 false)249 250// Force static initialization.251extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void252LLVMInitializeBPFAsmPrinter() {253 RegisterAsmPrinter<BPFAsmPrinter> X(getTheBPFleTarget());254 RegisterAsmPrinter<BPFAsmPrinter> Y(getTheBPFbeTarget());255 RegisterAsmPrinter<BPFAsmPrinter> Z(getTheBPFTarget());256}257