Example #1
0
/*
 * emit mov <ofs>(%<sreg>), %<dreg>
 * note that for non 64-bit ops, higher bits have to be cleared.
 */
static void
emit_ld_reg(struct bpf_jit_state *st, uint32_t op, uint32_t sreg, uint32_t dreg,
	int32_t ofs)
{
	uint32_t mods, opsz;
	const uint8_t op32 = 0x8B;
	const uint8_t op16[] = {0x0F, 0xB7};
	const uint8_t op8[] = {0x0F, 0xB6};

	emit_rex(st, op, dreg, sreg);

	opsz = BPF_SIZE(op);
	if (opsz == BPF_B)
		emit_bytes(st, op8, sizeof(op8));
	else if (opsz == BPF_H)
		emit_bytes(st, op16, sizeof(op16));
	else
		emit_bytes(st, &op32, sizeof(op32));

	mods = (imm_size(ofs) == 1) ? MOD_IDISP8 : MOD_IDISP32;

	emit_modregrm(st, mods, dreg, sreg);
	if (sreg == RSP || sreg == R12)
		emit_sib(st, SIB_SCALE_1, sreg, sreg);
	emit_imm(st, ofs, imm_size(ofs));
}
Example #2
0
/*
 * emit jmp <ofs>
 * where 'ofs' is the target offset for the native code.
 */
static void
emit_abs_jmp(struct bpf_jit_state *st, int32_t ofs)
{
	int32_t joff;
	uint32_t imsz;

	const uint8_t op8 = 0xEB;
	const uint8_t op32 = 0xE9;

	const int32_t sz8 = sizeof(op8) + sizeof(uint8_t);
	const int32_t sz32 = sizeof(op32) + sizeof(uint32_t);

	/* max possible jmp instruction size */
	const int32_t iszm = RTE_MAX(sz8, sz32);

	joff = ofs - st->sz;
	imsz = RTE_MAX(imm_size(joff), imm_size(joff + iszm));

	if (imsz == 1) {
		emit_bytes(st, &op8, sizeof(op8));
		joff -= sz8;
	} else {
		emit_bytes(st, &op32, sizeof(op32));
		joff -= sz32;
	}

	emit_imm(st, joff, imsz);
}
Example #3
0
/*
 * emit ror <imm8>, %<dreg>
 */
static void
emit_ror_imm(struct bpf_jit_state *st, uint32_t dreg, uint32_t imm)
{
	const uint8_t prfx = 0x66;
	const uint8_t ops = 0xC1;
	const uint8_t mods = 1;

	emit_bytes(st, &prfx, sizeof(prfx));
	emit_rex(st, BPF_ALU, 0, dreg);
	emit_bytes(st, &ops, sizeof(ops));
	emit_modregrm(st, MOD_DIRECT, mods, dreg);
	emit_imm(st, imm, imm_size(imm));
}
Example #4
0
/*
 * emit REX byte
 */
static void
emit_rex(struct bpf_jit_state *st, uint32_t op, uint32_t reg, uint32_t rm)
{
	uint8_t rex;

	/* mark operand registers as used*/
	USED(st->reguse, reg);
	USED(st->reguse, rm);

	rex = 0;
	if (BPF_CLASS(op) == EBPF_ALU64 ||
			op == (BPF_ST | BPF_MEM | EBPF_DW) ||
			op == (BPF_STX | BPF_MEM | EBPF_DW) ||
			op == (BPF_STX | EBPF_XADD | EBPF_DW) ||
			op == (BPF_LD | BPF_IMM | EBPF_DW) ||
			(BPF_CLASS(op) == BPF_LDX &&
			BPF_MODE(op) == BPF_MEM &&
			BPF_SIZE(op) != BPF_W))
		rex |= REX_W;

	if (IS_EXT_REG(reg))
		rex |= REX_R;

	if (IS_EXT_REG(rm))
		rex |= REX_B;

	/* store using SIL, DIL */
	if (op == (BPF_STX | BPF_MEM | BPF_B) && (reg == RDI || reg == RSI))
		rex |= REX_PREFIX;

	if (rex != 0) {
		rex |= REX_PREFIX;
		emit_bytes(st, &rex, sizeof(rex));
	}
}
Example #5
0
/*
 * emit one of:
 *   add <imm>, %<dreg>
 *   and <imm>, %<dreg>
 *   or  <imm>, %<dreg>
 *   sub <imm>, %<dreg>
 *   xor <imm>, %<dreg>
 */
static void
emit_alu_imm(struct bpf_jit_state *st, uint32_t op, uint32_t dreg, uint32_t imm)
{
	uint8_t mod, opcode;
	uint32_t bop, imsz;

	const uint8_t op8 = 0x83;
	const uint8_t op32 = 0x81;
	static const uint8_t mods[] = {
		[GET_BPF_OP(BPF_ADD)] = 0,
		[GET_BPF_OP(BPF_AND)] = 4,
		[GET_BPF_OP(BPF_OR)] =  1,
		[GET_BPF_OP(BPF_SUB)] = 5,
		[GET_BPF_OP(BPF_XOR)] = 6,
	};

	bop = GET_BPF_OP(op);
	mod = mods[bop];

	imsz = imm_size(imm);
	opcode = (imsz == 1) ? op8 : op32;

	emit_rex(st, op, 0, dreg);
	emit_bytes(st, &opcode, sizeof(opcode));
	emit_modregrm(st, MOD_DIRECT, mod, dreg);
	emit_imm(st, imm, imsz);
}
Example #6
0
/*
 * emit SIB byte
 */
static void
emit_sib(struct bpf_jit_state *st, uint32_t scale, uint32_t idx, uint32_t base)
{
	uint8_t v;

	v = scale << 6 | (idx & 7) << 3 | (base & 7);
	emit_bytes(st, &v, sizeof(v));
}
Example #7
0
/*
 * emit MODRegRM byte
 */
static void
emit_modregrm(struct bpf_jit_state *st, uint32_t mod, uint32_t reg, uint32_t rm)
{
	uint8_t v;

	v = mod << 6 | (reg & 7) << 3 | (rm & 7);
	emit_bytes(st, &v, sizeof(v));
}
Example #8
0
static void
emit_imm(struct bpf_jit_state *st, const uint32_t imm, uint32_t sz)
{
	union bpf_jit_imm v;

	v.u32 = imm;
	emit_bytes(st, v.u8, sz);
}
Example #9
0
/*
 * emit lock add %<sreg>, <ofs>(%<dreg>)
 */
static void
emit_st_xadd(struct bpf_jit_state *st, uint32_t op, uint32_t sreg,
	uint32_t dreg, int32_t ofs)
{
	uint32_t imsz, mods;

	const uint8_t lck = 0xF0; /* lock prefix */
	const uint8_t ops = 0x01; /* add opcode */

	imsz = imm_size(ofs);
	mods = (imsz == 1) ? MOD_IDISP8 : MOD_IDISP32;

	emit_bytes(st, &lck, sizeof(lck));
	emit_rex(st, op, sreg, dreg);
	emit_bytes(st, &ops, sizeof(ops));
	emit_modregrm(st, mods, sreg, dreg);
	emit_imm(st, ofs, imsz);
}
Example #10
0
/*
 * emit movzwl %<sreg>, %<dreg>
 */
static void
emit_movzwl(struct bpf_jit_state *st, uint32_t sreg, uint32_t dreg)
{
	static const uint8_t ops[] = {0x0F, 0xB7};

	emit_rex(st, BPF_ALU, sreg, dreg);
	emit_bytes(st, ops, sizeof(ops));
	emit_modregrm(st, MOD_DIRECT, sreg, dreg);
}
Example #11
0
/*
 * emit xchg %<sreg>, %<dreg>
 */
static void
emit_xchg_reg(struct bpf_jit_state *st, uint32_t sreg, uint32_t dreg)
{
	const uint8_t ops = 0x87;

	emit_rex(st, EBPF_ALU64, sreg, dreg);
	emit_bytes(st, &ops, sizeof(ops));
	emit_modregrm(st, MOD_DIRECT, sreg, dreg);
}
Example #12
0
/*
 * emit neg %<dreg>
 */
static void
emit_neg(struct bpf_jit_state *st, uint32_t op, uint32_t dreg)
{
	const uint8_t ops = 0xF7;
	const uint8_t mods = 3;

	emit_rex(st, op, 0, dreg);
	emit_bytes(st, &ops, sizeof(ops));
	emit_modregrm(st, MOD_DIRECT, mods, dreg);
}
Example #13
0
/*
 * emit:
 *    mov <imm64>, (%rax)
 *    call *%rax
 */
static void
emit_call(struct bpf_jit_state *st, uintptr_t trg)
{
	const uint8_t ops = 0xFF;
	const uint8_t mods = 2;

	emit_ld_imm64(st, RAX, trg, trg >> 32);
	emit_bytes(st, &ops, sizeof(ops));
	emit_modregrm(st, MOD_DIRECT, mods, RAX);
}
Example #14
0
/*
 * emit one of:
 *   mov %<sreg>, <ofs>(%<dreg>)
 *   mov <imm>, <ofs>(%<dreg>)
 */
static void
emit_st_common(struct bpf_jit_state *st, uint32_t op, uint32_t sreg,
	uint32_t dreg, uint32_t imm, int32_t ofs)
{
	uint32_t mods, imsz, opsz, opx;
	const uint8_t prfx16 = 0x66;

	/* 8 bit instruction opcodes */
	static const uint8_t op8[] = {0xC6, 0x88};

	/* 16/32/64 bit instruction opcodes */
	static const uint8_t ops[] = {0xC7, 0x89};

	/* is the instruction has immediate value or src reg? */
	opx = (BPF_CLASS(op) == BPF_STX);

	opsz = BPF_SIZE(op);
	if (opsz == BPF_H)
		emit_bytes(st, &prfx16, sizeof(prfx16));

	emit_rex(st, op, sreg, dreg);

	if (opsz == BPF_B)
		emit_bytes(st, &op8[opx], sizeof(op8[opx]));
	else
		emit_bytes(st, &ops[opx], sizeof(ops[opx]));

	imsz = imm_size(ofs);
	mods = (imsz == 1) ? MOD_IDISP8 : MOD_IDISP32;

	emit_modregrm(st, mods, sreg, dreg);

	if (dreg == RSP || dreg == R12)
		emit_sib(st, SIB_SCALE_1, dreg, dreg);

	emit_imm(st, ofs, imsz);

	if (opx == 0) {
		imsz = RTE_MIN(bpf_size(opsz), sizeof(imm));
		emit_imm(st, imm, imsz);
	}
}
Example #15
0
/*
 * emit bswap %<dreg>
 */
static void
emit_be2le_48(struct bpf_jit_state *st, uint32_t dreg, uint32_t imm)
{
	uint32_t rop;

	const uint8_t ops = 0x0F;
	const uint8_t mods = 1;

	rop = (imm == 64) ? EBPF_ALU64 : BPF_ALU;
	emit_rex(st, rop, 0, dreg);
	emit_bytes(st, &ops, sizeof(ops));
	emit_modregrm(st, MOD_DIRECT, mods, dreg);
}
Example #16
0
/*
 * emit mov %<sreg>, %<dreg>
 */
static void
emit_mov_reg(struct bpf_jit_state *st, uint32_t op, uint32_t sreg,
	uint32_t dreg)
{
	const uint8_t ops = 0x89;

	/* if operands are 32-bit, then it can be used to clear upper 32-bit */
	if (sreg != dreg || BPF_CLASS(op) == BPF_ALU) {
		emit_rex(st, op, sreg, dreg);
		emit_bytes(st, &ops, sizeof(ops));
		emit_modregrm(st, MOD_DIRECT, sreg, dreg);
	}
}
Example #17
0
/*
 * emit mov <imm>, %<dreg>
 */
static void
emit_mov_imm(struct bpf_jit_state *st, uint32_t op, uint32_t dreg, uint32_t imm)
{
	const uint8_t ops = 0xC7;

	if (imm == 0) {
		/* replace 'mov 0, %<dst>' with 'xor %<dst>, %<dst>' */
		op = BPF_CLASS(op) | BPF_XOR | BPF_X;
		emit_alu_reg(st, op, dreg, dreg);
		return;
	}

	emit_rex(st, op, 0, dreg);
	emit_bytes(st, &ops, sizeof(ops));
	emit_modregrm(st, MOD_DIRECT, 0, dreg);
	emit_imm(st, imm, sizeof(imm));
}
Example #18
0
/*
 * emit mov <imm64>, %<dreg>
 */
static void
emit_ld_imm64(struct bpf_jit_state *st, uint32_t dreg, uint32_t imm0,
	uint32_t imm1)
{
	const uint8_t ops = 0xB8;

	if (imm1 == 0) {
		emit_mov_imm(st, EBPF_ALU64 | EBPF_MOV | BPF_K, dreg, imm0);
		return;
	}

	emit_rex(st, EBPF_ALU64, 0, dreg);
	emit_bytes(st, &ops, sizeof(ops));
	emit_modregrm(st, MOD_DIRECT, 0, dreg);

	emit_imm(st, imm0, sizeof(imm0));
	emit_imm(st, imm1, sizeof(imm1));
}
Example #19
0
/*
 * emit one of:
 *   add %<sreg>, %<dreg>
 *   and %<sreg>, %<dreg>
 *   or  %<sreg>, %<dreg>
 *   sub %<sreg>, %<dreg>
 *   xor %<sreg>, %<dreg>
 */
static void
emit_alu_reg(struct bpf_jit_state *st, uint32_t op, uint32_t sreg,
	uint32_t dreg)
{
	uint32_t bop;

	static const uint8_t ops[] = {
		[GET_BPF_OP(BPF_ADD)] = 0x01,
		[GET_BPF_OP(BPF_AND)] = 0x21,
		[GET_BPF_OP(BPF_OR)] =  0x09,
		[GET_BPF_OP(BPF_SUB)] = 0x29,
		[GET_BPF_OP(BPF_XOR)] = 0x31,
	};

	bop = GET_BPF_OP(op);

	emit_rex(st, op, sreg, dreg);
	emit_bytes(st, &ops[bop], sizeof(ops[bop]));
	emit_modregrm(st, MOD_DIRECT, sreg, dreg);
}
Example #20
0
static void
emit_shift(struct bpf_jit_state *st, uint32_t op, uint32_t dreg)
{
	uint8_t mod;
	uint32_t bop, opx;

	static const uint8_t ops[] = {0xC1, 0xD3};
	static const uint8_t mods[] = {
		[GET_BPF_OP(BPF_LSH)] = 4,
		[GET_BPF_OP(BPF_RSH)] = 5,
		[GET_BPF_OP(EBPF_ARSH)] = 7,
	};

	bop = GET_BPF_OP(op);
	mod = mods[bop];
	opx = (BPF_SRC(op) == BPF_X);

	emit_rex(st, op, 0, dreg);
	emit_bytes(st, &ops[opx], sizeof(ops[opx]));
	emit_modregrm(st, MOD_DIRECT, mod, dreg);
}
Example #21
0
/*
 * note that rax:rdx are implicitly used as source/destination registers,
 * so some reg spillage is necessary.
 * emit:
 * mov %rax, %r11
 * mov %rdx, %r10
 * mov %<dreg>, %rax
 * either:
 *   mov %<sreg>, %rdx
 * OR
 *   mov <imm>, %rdx
 * mul %rdx
 * mov %r10, %rdx
 * mov %rax, %<dreg>
 * mov %r11, %rax
 */
static void
emit_mul(struct bpf_jit_state *st, uint32_t op, uint32_t sreg, uint32_t dreg,
	uint32_t imm)
{
	const uint8_t ops = 0xF7;
	const uint8_t mods = 4;

	/* save rax & rdx */
	emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X, RAX, REG_TMP0);
	emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X, RDX, REG_TMP1);

	/* rax = dreg */
	emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X, dreg, RAX);

	if (BPF_SRC(op) == BPF_X)
		/* rdx = sreg */
		emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X,
			sreg == RAX ? REG_TMP0 : sreg, RDX);
	else
		/* rdx = imm */
		emit_mov_imm(st, EBPF_ALU64 | EBPF_MOV | BPF_K, RDX, imm);

	emit_rex(st, op, RAX, RDX);
	emit_bytes(st, &ops, sizeof(ops));
	emit_modregrm(st, MOD_DIRECT, mods, RDX);

	if (dreg != RDX)
		/* restore rdx */
		emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X, REG_TMP1, RDX);

	if (dreg != RAX) {
		/* dreg = rax */
		emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X, RAX, dreg);
		/* restore rax */
		emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X, REG_TMP0, RAX);
	}
}
Example #22
0
static void emit_constant(Value value)
{
	emit_bytes(OP_CONSTANT, make_constant(value));
}