forked from Imagelibrary/binutils-gdb
This patch adds support for EF_BPF_CPUVER bits in the ELF
machine-dependent header flags. These bits encode the BPF CPU
version for which the object file has been compiled for.
The BPF assembler is updated so it annotates the object files it
generates with these bits.
The BPF disassembler is updated so it honors EF_BPF_CPUVER to use the
appropriate ISA version if the user didn't specify an explicit ISA
version in the command line. Note that a value of zero in
EF_BPF_CPUVER is interpreted by the disassembler as "use the later
supported version" (the BPF CPU versions start with v1.)
The readelf utility is updated to pretty print EF_BPF_CPUVER when it
prints out the ELF header:
$ readelf -h a.out
ELF Header:
...
Flags: 0x4, CPU Version: 4
Tested in bpf-unknown-none.
include/ChangeLog:
2023-07-30 Jose E. Marchesi <jose.marchesi@oracle.com>
* elf/bpf.h (EF_BPF_CPUVER): Define.
* opcode/bpf.h (BPF_XBPF): Change from 0xf to 0xff so it fits in
EF_BPF_CPUVER.
binutils/ChangeLog:
2023-07-30 Jose E. Marchesi <jose.marchesi@oracle.com>
* readelf.c (get_machine_flags): Recognize and pretty print BPF
machine flags.
opcodes/ChangeLog:
2023-07-30 Jose E. Marchesi <jose.marchesi@oracle.com>
* bpf-dis.c: Initialize asm_bpf_version to -1.
(print_insn_bpf): Set BPF ISA version from the cpu version ELF
header flags if no explicit version set in the command line.
* disassemble.c (disassemble_init_for_target): Remove unused code.
gas/ChangeLog:
2023-07-30 Jose E. Marchesi <jose.marchesi@oracle.com>
* config/tc-bpf.h (elf_tc_final_processing): Define.
* config/tc-bpf.c (bpf_elf_final_processing): New function.
326 lines
13 KiB
C
326 lines
13 KiB
C
/* bpf.h - BPF opcode list for binutils.
|
|
Copyright (C) 2023 Free Software Foundation, Inc.
|
|
|
|
Contributed by Oracle Inc.
|
|
|
|
This file is part of the GNU binutils.
|
|
|
|
This is free software; you can redistribute them and/or modify them
|
|
under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; see the file COPYING3. If not,
|
|
see <http://www.gnu.org/licenses/>. */
|
|
|
|
#ifndef _BPF_H_
|
|
#define _BPF_H_
|
|
|
|
#include <stdint.h>
|
|
|
|
/* The BPF ISA has little-endian and big-endian variants. */
|
|
|
|
enum bpf_endian
|
|
{
|
|
BPF_ENDIAN_LITTLE,
|
|
BPF_ENDIAN_BIG
|
|
};
|
|
|
|
/* Most BPF instructions are conformed by a single 64-bit instruction
|
|
word. The lddw instruction is conformed by two consecutive 64-bit
|
|
instruction words. */
|
|
|
|
typedef uint64_t bpf_insn_word;
|
|
|
|
/* There are several versions of the BPF ISA. */
|
|
|
|
#define BPF_V1 0x1
|
|
#define BPF_V2 0x2
|
|
#define BPF_V3 0x3
|
|
#define BPF_V4 0x4
|
|
#define BPF_XBPF 0xf
|
|
|
|
/* Masks for the several instruction fields in a BPF instruction.
|
|
These assume big-endian BPF instructions. */
|
|
|
|
#define BPF_CODE 0xff00000000000000UL
|
|
#define BPF_REGS 0x00ff000000000000UL
|
|
#define BPF_DST 0x00f0000000000000UL
|
|
#define BPF_SRC 0x000f000000000000UL
|
|
#define BPF_OFFSET16 0x0000ffff00000000UL
|
|
#define BPF_IMM32 0x00000000ffffffffUL
|
|
|
|
/* The BPF opcode instruction field is eight bits long and its
|
|
interpretation depends on the instruction class.
|
|
|
|
For arithmetic and jump instructions the 8-bit opcode field is
|
|
subdivided in:
|
|
|
|
op-code:4 op-src:1 op-class:3
|
|
|
|
For load/store instructions, the 8-bit opcode field is subdivided
|
|
in:
|
|
|
|
op-mode:3 op-size:2 op-class:3
|
|
|
|
All the constants defined below are to be applied on the first
|
|
64-bit word of a BPF instruction. Please define them assuming
|
|
big-endian instructions; the matching and writing routines using
|
|
the instruction table know how to handle the endianness groups. */
|
|
|
|
#define BPF_SRC_X ((uint64_t)0x08 << 56)
|
|
#define BPF_SRC_K ((uint64_t)0x00 << 56)
|
|
|
|
#define BPF_CODE_ADD ((uint64_t)0x00 << 56)
|
|
#define BPF_CODE_SUB ((uint64_t)0x10 << 56)
|
|
#define BPF_CODE_MUL ((uint64_t)0x20 << 56)
|
|
#define BPF_CODE_DIV ((uint64_t)0x30 << 56)
|
|
#define BPF_CODE_OR ((uint64_t)0x40 << 56)
|
|
#define BPF_CODE_AND ((uint64_t)0x50 << 56)
|
|
#define BPF_CODE_LSH ((uint64_t)0x60 << 56)
|
|
#define BPF_CODE_RSH ((uint64_t)0x70 << 56)
|
|
#define BPF_CODE_NEG ((uint64_t)0x80 << 56)
|
|
#define BPF_CODE_MOD ((uint64_t)0x90 << 56)
|
|
#define BPF_CODE_XOR ((uint64_t)0xa0 << 56)
|
|
#define BPF_CODE_MOV ((uint64_t)0xb0 << 56)
|
|
#define BPF_CODE_ARSH ((uint64_t)0xc0 << 56)
|
|
#define BPF_CODE_END ((uint64_t)0xd0 << 56)
|
|
|
|
#define BPF_CODE_JA ((uint64_t)0x00 << 56)
|
|
#define BPF_CODE_JEQ ((uint64_t)0x10 << 56)
|
|
#define BPF_CODE_JGT ((uint64_t)0x20 << 56)
|
|
#define BPF_CODE_JGE ((uint64_t)0x30 << 56)
|
|
#define BPF_CODE_JSET ((uint64_t)0x40 << 56)
|
|
#define BPF_CODE_JNE ((uint64_t)0x50 << 56)
|
|
#define BPF_CODE_JSGT ((uint64_t)0x60 << 56)
|
|
#define BPF_CODE_JSGE ((uint64_t)0x70 << 56)
|
|
#define BPF_CODE_CALL ((uint64_t)0x80 << 56)
|
|
#define BPF_CODE_EXIT ((uint64_t)0x90 << 56)
|
|
#define BPF_CODE_JLT ((uint64_t)0xa0 << 56)
|
|
#define BPF_CODE_JLE ((uint64_t)0xb0 << 56)
|
|
#define BPF_CODE_JSLT ((uint64_t)0xc0 << 56)
|
|
#define BPF_CODE_JSLE ((uint64_t)0xd0 << 56)
|
|
|
|
#define BPF_MODE_IMM ((uint64_t)0x00 << 56)
|
|
#define BPF_MODE_ABS ((uint64_t)0x20 << 56)
|
|
#define BPF_MODE_IND ((uint64_t)0x40 << 56)
|
|
#define BPF_MODE_MEM ((uint64_t)0x60 << 56)
|
|
#define BPF_MODE_ATOMIC ((uint64_t)0xc0 << 56)
|
|
#define BPF_MODE_SMEM ((uint64_t)0x80 << 56)
|
|
|
|
#define BPF_SIZE_W ((uint64_t)0x00 << 56)
|
|
#define BPF_SIZE_H ((uint64_t)0x08 << 56)
|
|
#define BPF_SIZE_B ((uint64_t)0x10 << 56)
|
|
#define BPF_SIZE_DW ((uint64_t)0x18 << 56)
|
|
|
|
#define BPF_CLASS_LD ((uint64_t)0x00 << 56)
|
|
#define BPF_CLASS_LDX ((uint64_t)0x01 << 56)
|
|
#define BPF_CLASS_ST ((uint64_t)0x02 << 56)
|
|
#define BPF_CLASS_STX ((uint64_t)0x03 << 56)
|
|
#define BPF_CLASS_ALU ((uint64_t)0x04 << 56)
|
|
#define BPF_CLASS_JMP ((uint64_t)0x05 << 56)
|
|
#define BPF_CLASS_JMP32 ((uint64_t)0x06 << 56)
|
|
#define BPF_CLASS_ALU64 ((uint64_t)0x07 << 56)
|
|
|
|
/* Certain instructions (ab)use other instruction fields as opcodes,
|
|
even if these are multi-byte or infra-byte. Bleh. */
|
|
|
|
#define BPF_OFFSET16_SDIVMOD ((uint64_t)0x1 << 32)
|
|
#define BPF_OFFSET16_MOVS8 ((uint64_t)8 << 32)
|
|
#define BPF_OFFSET16_MOVS16 ((uint64_t)16 << 32)
|
|
#define BPF_OFFSET16_MOVS32 ((uint64_t)32 << 32)
|
|
|
|
#define BPF_IMM32_END16 ((uint64_t)0x00000010)
|
|
#define BPF_IMM32_END32 ((uint64_t)0x00000020)
|
|
#define BPF_IMM32_END64 ((uint64_t)0x00000040)
|
|
|
|
#define BPF_IMM32_BSWAP16 ((uint64_t)0x00000010)
|
|
#define BPF_IMM32_BSWAP32 ((uint64_t)0x00000020)
|
|
#define BPF_IMM32_BSWAP64 ((uint64_t)0x00000040)
|
|
|
|
#define BPF_IMM32_AADD ((uint64_t)0x00000000)
|
|
#define BPF_IMM32_AOR ((uint64_t)0x00000040)
|
|
#define BPF_IMM32_AAND ((uint64_t)0x00000050)
|
|
#define BPF_IMM32_AXOR ((uint64_t)0x000000a0)
|
|
#define BPF_IMM32_AFADD ((uint64_t)0x00000001)
|
|
#define BPF_IMM32_AFOR ((uint64_t)0x00000041)
|
|
#define BPF_IMM32_AFAND ((uint64_t)0x00000051)
|
|
#define BPF_IMM32_AFXOR ((uint64_t)0x000000a1)
|
|
#define BPF_IMM32_AXCHG ((uint64_t)0x000000e1)
|
|
#define BPF_IMM32_ACMP ((uint64_t)0x000000f1)
|
|
|
|
/* Unique identifiers for BPF instructions. */
|
|
|
|
enum bpf_insn_id
|
|
{
|
|
BPF_NOINSN = 0,
|
|
/* 64-bit load instruction. */
|
|
BPF_INSN_LDDW,
|
|
/* ALU instructions. */
|
|
BPF_INSN_ADDR, BPF_INSN_ADDI, BPF_INSN_SUBR, BPF_INSN_SUBI,
|
|
BPF_INSN_MULR, BPF_INSN_MULI, BPF_INSN_SDIVR, BPF_INSN_SDIVI,
|
|
BPF_INSN_SMODR, BPF_INSN_SMODI, BPF_INSN_DIVR, BPF_INSN_DIVI,
|
|
BPF_INSN_MODR, BPF_INSN_MODI, BPF_INSN_ORR, BPF_INSN_ORI,
|
|
BPF_INSN_ANDR, BPF_INSN_ANDI, BPF_INSN_XORR, BPF_INSN_XORI,
|
|
BPF_INSN_NEGR, BPF_INSN_NEGI, BPF_INSN_LSHR, BPF_INSN_LSHI,
|
|
BPF_INSN_RSHR, BPF_INSN_RSHI, BPF_INSN_ARSHR, BPF_INSN_ARSHI,
|
|
BPF_INSN_MOVS8R, BPF_INSN_MOVS16R, BPF_INSN_MOVS32R,
|
|
BPF_INSN_MOVR, BPF_INSN_MOVI,
|
|
/* ALU32 instructions. */
|
|
BPF_INSN_ADD32R, BPF_INSN_ADD32I, BPF_INSN_SUB32R, BPF_INSN_SUB32I,
|
|
BPF_INSN_MUL32R, BPF_INSN_MUL32I, BPF_INSN_SDIV32R, BPF_INSN_SDIV32I,
|
|
BPF_INSN_SMOD32R, BPF_INSN_SMOD32I, BPF_INSN_DIV32R, BPF_INSN_DIV32I,
|
|
BPF_INSN_MOD32R, BPF_INSN_MOD32I, BPF_INSN_OR32R, BPF_INSN_OR32I,
|
|
BPF_INSN_AND32R, BPF_INSN_AND32I, BPF_INSN_XOR32R, BPF_INSN_XOR32I,
|
|
BPF_INSN_NEG32R, BPF_INSN_NEG32I, BPF_INSN_LSH32R, BPF_INSN_LSH32I,
|
|
BPF_INSN_RSH32R, BPF_INSN_RSH32I, BPF_INSN_ARSH32R, BPF_INSN_ARSH32I,
|
|
BPF_INSN_MOVS328R, BPF_INSN_MOVS3216R, BPF_INSN_MOVS3232R,
|
|
BPF_INSN_MOV32R, BPF_INSN_MOV32I,
|
|
/* Byte swap instructions. */
|
|
BPF_INSN_BSWAP16, BPF_INSN_BSWAP32, BPF_INSN_BSWAP64,
|
|
/* Endianness conversion instructions. */
|
|
BPF_INSN_ENDLE16, BPF_INSN_ENDLE32, BPF_INSN_ENDLE64,
|
|
BPF_INSN_ENDBE16, BPF_INSN_ENDBE32, BPF_INSN_ENDBE64,
|
|
/* Absolute load instructions. */
|
|
BPF_INSN_LDABSB, BPF_INSN_LDABSH, BPF_INSN_LDABSW, BPF_INSN_LDABSDW,
|
|
/* Indirect load instructions. */
|
|
BPF_INSN_LDINDB, BPF_INSN_LDINDH, BPF_INSN_LDINDW, BPF_INSN_LDINDDW,
|
|
/* Generic load instructions (to register.) */
|
|
BPF_INSN_LDXB, BPF_INSN_LDXH, BPF_INSN_LDXW, BPF_INSN_LDXDW,
|
|
/* Generic signed load instructions. */
|
|
BPF_INSN_LDXSB, BPF_INSN_LDXSH, BPF_INSN_LDXSW, BPF_INSN_LDXSDW,
|
|
/* Generic store instructions (from register.) */
|
|
BPF_INSN_STXBR, BPF_INSN_STXHR, BPF_INSN_STXWR, BPF_INSN_STXDWR,
|
|
BPF_INSN_STXBI, BPF_INSN_STXHI, BPF_INSN_STXWI, BPF_INSN_STXDWI,
|
|
/* Compare-and-jump instructions (reg OP reg.) */
|
|
BPF_INSN_JAR, BPF_INSN_JEQR, BPF_INSN_JGTR, BPF_INSN_JSGTR,
|
|
BPF_INSN_JGER, BPF_INSN_JSGER, BPF_INSN_JLTR, BPF_INSN_JSLTR,
|
|
BPF_INSN_JSLER, BPF_INSN_JLER, BPF_INSN_JSETR, BPF_INSN_JNER,
|
|
BPF_INSN_CALLR, BPF_INSN_CALL, BPF_INSN_EXIT,
|
|
/* Compare-and-jump instructions (reg OP imm.) */
|
|
BPF_INSN_JEQI, BPF_INSN_JGTI, BPF_INSN_JSGTI,
|
|
BPF_INSN_JGEI, BPF_INSN_JSGEI, BPF_INSN_JLTI, BPF_INSN_JSLTI,
|
|
BPF_INSN_JSLEI, BPF_INSN_JLEI, BPF_INSN_JSETI, BPF_INSN_JNEI,
|
|
/* jump-always with 32-bit offset. */
|
|
BPF_INSN_JAL,
|
|
/* 32-bit compare-and-jump instructions (reg OP reg.) */
|
|
BPF_INSN_JEQ32R, BPF_INSN_JGT32R, BPF_INSN_JSGT32R,
|
|
BPF_INSN_JGE32R, BPF_INSN_JSGE32R, BPF_INSN_JLT32R, BPF_INSN_JSLT32R,
|
|
BPF_INSN_JSLE32R, BPF_INSN_JLE32R, BPF_INSN_JSET32R, BPF_INSN_JNE32R,
|
|
/* 32-bit compare-and-jump instructions (reg OP imm.) */
|
|
BPF_INSN_JEQ32I, BPF_INSN_JGT32I, BPF_INSN_JSGT32I,
|
|
BPF_INSN_JGE32I, BPF_INSN_JSGE32I, BPF_INSN_JLT32I, BPF_INSN_JSLT32I,
|
|
BPF_INSN_JSLE32I, BPF_INSN_JLE32I, BPF_INSN_JSET32I, BPF_INSN_JNE32I,
|
|
/* Atomic instructions. */
|
|
BPF_INSN_AADD, BPF_INSN_AOR, BPF_INSN_AAND, BPF_INSN_AXOR,
|
|
/* Atomic instructions with fetching. */
|
|
BPF_INSN_AFADD, BPF_INSN_AFOR, BPF_INSN_AFAND, BPF_INSN_AFXOR,
|
|
/* Atomic instructions (32-bit.) */
|
|
BPF_INSN_AADD32, BPF_INSN_AOR32, BPF_INSN_AAND32, BPF_INSN_AXOR32,
|
|
/* Atomic instructions with fetching (32-bit.) */
|
|
BPF_INSN_AFADD32, BPF_INSN_AFOR32, BPF_INSN_AFAND32, BPF_INSN_AFXOR32,
|
|
/* Atomic compare-and-swap, atomic exchange. */
|
|
BPF_INSN_ACMP, BPF_INSN_AXCHG,
|
|
/* Atomic compare-and-swap, atomic exchange (32-bit). */
|
|
BPF_INSN_ACMP32, BPF_INSN_AXCHG32,
|
|
/* GNU simulator specific instruction. */
|
|
BPF_INSN_BRKPT,
|
|
};
|
|
|
|
/* Entry for a BPF instruction in the opcodes table. */
|
|
|
|
struct bpf_opcode
|
|
{
|
|
/* Unique numerical code for the instruction. */
|
|
enum bpf_insn_id id;
|
|
|
|
/* The instruction template defines both the syntax of the
|
|
instruction and the set of the different operands that appear in
|
|
the instruction.
|
|
|
|
Tags:
|
|
%% - literal %.
|
|
%dr - destination 64-bit register.
|
|
%dw - destination 32-bit register.
|
|
%sr - source 64-bit register.
|
|
%sw - source 32-bit register.
|
|
%d32 - 32-bit signed displacement (in 64-bit words minus one.)
|
|
%d16 - 16-bit signed displacement (in 64-bit words minus one.)
|
|
%o16 - 16-bit signed offset (in bytes.)
|
|
%i32 - 32-bit signed immediate.
|
|
%I32 - Like %i32.
|
|
%i64 - 64-bit signed immediate.
|
|
%w - expect zero or more white spaces and print a single space.
|
|
%W - expect one or more white spaces and print a single space.
|
|
|
|
When parsing and printing %o16 and %I32 (but not %i32) an
|
|
explicit sign is always expected and included. Therefore, to
|
|
denote something like `[%r3 + 10]', please use a template like `[
|
|
%sr %o16]' instead of `[ %sr + %o16 ]'.
|
|
|
|
If %dr, %dw, %sr or %sw are found multiple times in a template,
|
|
they refer to the same register, i.e. `%rd = le64 %rd' denotes
|
|
`r2 = le64 r2', but not `r2 = le64 r1'.
|
|
|
|
If %i64 appears in a template then the instruction is 128-bits
|
|
long and composed by two consecutive 64-bit instruction words.
|
|
|
|
A white space character means to expect zero or more white
|
|
spaces, and to print no space.
|
|
|
|
There are two templates defined per instruction, corresponding to
|
|
two used different dialects: a "normal" assembly-like syntax and
|
|
a "pseudo-c" syntax. Some toolchains support just one of these
|
|
dialects. The GNU Toolchain supports both. */
|
|
const char *normal;
|
|
const char *pseudoc;
|
|
|
|
/* The version that introduced this instruction. Instructions are
|
|
generally not removed once they get introduced. */
|
|
uint8_t version;
|
|
|
|
/* Maks marking the opcode fields in the instruction, and the
|
|
opcodes characterizing it.
|
|
|
|
In multi-word instructions these apply to the first word in the
|
|
instruction. Note that these values assumes big-endian
|
|
instructions; code using these field must be aware of the
|
|
endianness groups to which BPF instructions must conform to and
|
|
DTRT. */
|
|
bpf_insn_word mask;
|
|
bpf_insn_word opcode;
|
|
};
|
|
|
|
/* Try to match a BPF instruction given its first instruction word.
|
|
If no matching instruction is found, return NULL. */
|
|
|
|
const struct bpf_opcode *bpf_match_insn (bpf_insn_word word,
|
|
enum bpf_endian endian,
|
|
int version);
|
|
|
|
/* Operand extractors.
|
|
|
|
These all get big-endian instruction words. Note how the extractor
|
|
for 64-bit signed immediates requires two instruction words. */
|
|
|
|
uint8_t bpf_extract_src (bpf_insn_word word, enum bpf_endian endian);
|
|
uint8_t bpf_extract_dst (bpf_insn_word word, enum bpf_endian endian);
|
|
int16_t bpf_extract_offset16 (bpf_insn_word word, enum bpf_endian endian);
|
|
int32_t bpf_extract_imm32 (bpf_insn_word word, enum bpf_endian endian);
|
|
int64_t bpf_extract_imm64 (bpf_insn_word word1, bpf_insn_word word2,
|
|
enum bpf_endian endian);
|
|
|
|
/* Get the opcode occupying the INDEX position in the opcodes table.
|
|
The INDEX is zero based. If the provided index overflows the
|
|
opcodes table then NULL is returned. */
|
|
|
|
const struct bpf_opcode *bpf_get_opcode (unsigned int index);
|
|
|
|
#endif /* !_BPF_H_ */
|