187 lines · cpp
1//===-- BPFMCCodeEmitter.cpp - Convert BPF code to machine code -----------===//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 implements the BPFMCCodeEmitter class.10//11//===----------------------------------------------------------------------===//12 13#include "MCTargetDesc/BPFMCFixups.h"14#include "MCTargetDesc/BPFMCTargetDesc.h"15#include "llvm/ADT/SmallVector.h"16#include "llvm/MC/MCCodeEmitter.h"17#include "llvm/MC/MCContext.h"18#include "llvm/MC/MCExpr.h"19#include "llvm/MC/MCFixup.h"20#include "llvm/MC/MCInst.h"21#include "llvm/MC/MCInstrInfo.h"22#include "llvm/MC/MCRegisterInfo.h"23#include "llvm/MC/MCSubtargetInfo.h"24#include "llvm/Support/EndianStream.h"25#include <cassert>26#include <cstdint>27 28using namespace llvm;29 30#define DEBUG_TYPE "mccodeemitter"31 32namespace {33 34class BPFMCCodeEmitter : public MCCodeEmitter {35 const MCRegisterInfo &MRI;36 bool IsLittleEndian;37 MCContext &Ctx;38 39public:40 BPFMCCodeEmitter(const MCInstrInfo &, const MCRegisterInfo &mri,41 bool IsLittleEndian, MCContext &ctx)42 : MRI(mri), IsLittleEndian(IsLittleEndian), Ctx(ctx) {}43 BPFMCCodeEmitter(const BPFMCCodeEmitter &) = delete;44 void operator=(const BPFMCCodeEmitter &) = delete;45 ~BPFMCCodeEmitter() override = default;46 47 // getBinaryCodeForInstr - TableGen'erated function for getting the48 // binary encoding for an instruction.49 uint64_t getBinaryCodeForInstr(const MCInst &MI,50 SmallVectorImpl<MCFixup> &Fixups,51 const MCSubtargetInfo &STI) const;52 53 // getMachineOpValue - Return binary encoding of operand. If the machin54 // operand requires relocation, record the relocation and return zero.55 unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,56 SmallVectorImpl<MCFixup> &Fixups,57 const MCSubtargetInfo &STI) const;58 59 uint64_t getMemoryOpValue(const MCInst &MI, unsigned Op,60 SmallVectorImpl<MCFixup> &Fixups,61 const MCSubtargetInfo &STI) const;62 63 void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,64 SmallVectorImpl<MCFixup> &Fixups,65 const MCSubtargetInfo &STI) const override;66};67 68} // end anonymous namespace69 70MCCodeEmitter *llvm::createBPFMCCodeEmitter(const MCInstrInfo &MCII,71 MCContext &Ctx) {72 return new BPFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), true, Ctx);73}74 75MCCodeEmitter *llvm::createBPFbeMCCodeEmitter(const MCInstrInfo &MCII,76 MCContext &Ctx) {77 return new BPFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), false, Ctx);78}79 80static void addFixup(SmallVectorImpl<MCFixup> &Fixups, uint32_t Offset,81 const MCExpr *Value, uint16_t Kind, bool PCRel = false) {82 Fixups.push_back(MCFixup::create(Offset, Value, Kind, PCRel));83}84 85unsigned BPFMCCodeEmitter::getMachineOpValue(const MCInst &MI,86 const MCOperand &MO,87 SmallVectorImpl<MCFixup> &Fixups,88 const MCSubtargetInfo &STI) const {89 if (MO.isReg())90 return MRI.getEncodingValue(MO.getReg());91 if (MO.isImm()) {92 uint64_t Imm = MO.getImm();93 uint64_t High32Bits = Imm >> 32, High33Bits = Imm >> 31;94 if (MI.getOpcode() != BPF::LD_imm64 && High32Bits != 0 &&95 High33Bits != 0x1FFFFFFFFULL) {96 Ctx.reportWarning(MI.getLoc(),97 "immediate out of range, shall fit in 32 bits");98 }99 return static_cast<unsigned>(Imm);100 }101 102 assert(MO.isExpr());103 104 const MCExpr *Expr = MO.getExpr();105 106 assert(Expr->getKind() == MCExpr::SymbolRef);107 108 if (MI.getOpcode() == BPF::JAL)109 // func call name110 addFixup(Fixups, 0, Expr, FK_Data_4, true);111 else if (MI.getOpcode() == BPF::LD_imm64)112 addFixup(Fixups, 0, Expr, FK_SecRel_8);113 else if (MI.getOpcode() == BPF::JMPL)114 addFixup(Fixups, 0, Expr, BPF::FK_BPF_PCRel_4, true);115 else116 // bb label117 addFixup(Fixups, 0, Expr, FK_Data_2, true);118 119 return 0;120}121 122static uint8_t SwapBits(uint8_t Val)123{124 return (Val & 0x0F) << 4 | (Val & 0xF0) >> 4;125}126 127void BPFMCCodeEmitter::encodeInstruction(const MCInst &MI,128 SmallVectorImpl<char> &CB,129 SmallVectorImpl<MCFixup> &Fixups,130 const MCSubtargetInfo &STI) const {131 unsigned Opcode = MI.getOpcode();132 raw_svector_ostream OS(CB);133 support::endian::Writer OSE(OS, IsLittleEndian ? llvm::endianness::little134 : llvm::endianness::big);135 136 if (Opcode == BPF::LD_imm64 || Opcode == BPF::LD_pseudo) {137 uint64_t Value = getBinaryCodeForInstr(MI, Fixups, STI);138 CB.push_back(Value >> 56);139 if (IsLittleEndian)140 CB.push_back((Value >> 48) & 0xff);141 else142 CB.push_back(SwapBits((Value >> 48) & 0xff));143 OSE.write<uint16_t>(0);144 OSE.write<uint32_t>(Value & 0xffffFFFF);145 146 const MCOperand &MO = MI.getOperand(1);147 uint64_t Imm = MO.isImm() ? MO.getImm() : 0;148 OSE.write<uint8_t>(0);149 OSE.write<uint8_t>(0);150 OSE.write<uint16_t>(0);151 OSE.write<uint32_t>(Imm >> 32);152 } else {153 // Get instruction encoding and emit it154 uint64_t Value = getBinaryCodeForInstr(MI, Fixups, STI);155 CB.push_back(Value >> 56);156 if (IsLittleEndian)157 CB.push_back(char((Value >> 48) & 0xff));158 else159 CB.push_back(SwapBits((Value >> 48) & 0xff));160 OSE.write<uint16_t>((Value >> 32) & 0xffff);161 OSE.write<uint32_t>(Value & 0xffffFFFF);162 }163}164 165// Encode BPF Memory Operand166uint64_t BPFMCCodeEmitter::getMemoryOpValue(const MCInst &MI, unsigned Op,167 SmallVectorImpl<MCFixup> &Fixups,168 const MCSubtargetInfo &STI) const {169 // For CMPXCHG instructions, output is implicitly in R0/W0,170 // so memory operand starts from operand 0.171 int MemOpStartIndex = 1, Opcode = MI.getOpcode();172 if (Opcode == BPF::CMPXCHGW32 || Opcode == BPF::CMPXCHGD)173 MemOpStartIndex = 0;174 175 uint64_t Encoding;176 const MCOperand Op1 = MI.getOperand(MemOpStartIndex);177 assert(Op1.isReg() && "First operand is not register.");178 Encoding = MRI.getEncodingValue(Op1.getReg());179 Encoding <<= 16;180 MCOperand Op2 = MI.getOperand(MemOpStartIndex + 1);181 assert(Op2.isImm() && "Second operand is not immediate.");182 Encoding |= Op2.getImm() & 0xffff;183 return Encoding;184}185 186#include "BPFGenMCCodeEmitter.inc"187