static int do_jit()

in arch/x86/net/bpf_jit_comp32.c [1462:2292]


static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
		  int oldproglen, struct jit_context *ctx)
{
	struct bpf_insn *insn = bpf_prog->insnsi;
	int insn_cnt = bpf_prog->len;
	bool seen_exit = false;
	u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY];
	int i, cnt = 0;
	int proglen = 0;
	u8 *prog = temp;

	emit_prologue(&prog, bpf_prog->aux->stack_depth);

	for (i = 0; i < insn_cnt; i++, insn++) {
		const s32 imm32 = insn->imm;
		const bool is64 = BPF_CLASS(insn->code) == BPF_ALU64;
		const bool dstk = insn->dst_reg == BPF_REG_AX ? false : true;
		const bool sstk = insn->src_reg == BPF_REG_AX ? false : true;
		const u8 code = insn->code;
		const u8 *dst = bpf2ia32[insn->dst_reg];
		const u8 *src = bpf2ia32[insn->src_reg];
		const u8 *r0 = bpf2ia32[BPF_REG_0];
		s64 jmp_offset;
		u8 jmp_cond;
		int ilen;
		u8 *func;

		switch (code) {
		/* ALU operations */
		/* dst = src */
		case BPF_ALU | BPF_MOV | BPF_K:
		case BPF_ALU | BPF_MOV | BPF_X:
		case BPF_ALU64 | BPF_MOV | BPF_K:
		case BPF_ALU64 | BPF_MOV | BPF_X:
			switch (BPF_SRC(code)) {
			case BPF_X:
				if (imm32 == 1) {
					/* Special mov32 for zext. */
					emit_ia32_mov_i(dst_hi, 0, dstk, &prog);
					break;
				}
				emit_ia32_mov_r64(is64, dst, src, dstk, sstk,
						  &prog, bpf_prog->aux);
				break;
			case BPF_K:
				/* Sign-extend immediate value to dst reg */
				emit_ia32_mov_i64(is64, dst, imm32,
						  dstk, &prog);
				break;
			}
			break;
		/* dst = dst + src/imm */
		/* dst = dst - src/imm */
		/* dst = dst | src/imm */
		/* dst = dst & src/imm */
		/* dst = dst ^ src/imm */
		/* dst = dst * src/imm */
		/* dst = dst << src */
		/* dst = dst >> src */
		case BPF_ALU | BPF_ADD | BPF_K:
		case BPF_ALU | BPF_ADD | BPF_X:
		case BPF_ALU | BPF_SUB | BPF_K:
		case BPF_ALU | BPF_SUB | BPF_X:
		case BPF_ALU | BPF_OR | BPF_K:
		case BPF_ALU | BPF_OR | BPF_X:
		case BPF_ALU | BPF_AND | BPF_K:
		case BPF_ALU | BPF_AND | BPF_X:
		case BPF_ALU | BPF_XOR | BPF_K:
		case BPF_ALU | BPF_XOR | BPF_X:
		case BPF_ALU64 | BPF_ADD | BPF_K:
		case BPF_ALU64 | BPF_ADD | BPF_X:
		case BPF_ALU64 | BPF_SUB | BPF_K:
		case BPF_ALU64 | BPF_SUB | BPF_X:
		case BPF_ALU64 | BPF_OR | BPF_K:
		case BPF_ALU64 | BPF_OR | BPF_X:
		case BPF_ALU64 | BPF_AND | BPF_K:
		case BPF_ALU64 | BPF_AND | BPF_X:
		case BPF_ALU64 | BPF_XOR | BPF_K:
		case BPF_ALU64 | BPF_XOR | BPF_X:
			switch (BPF_SRC(code)) {
			case BPF_X:
				emit_ia32_alu_r64(is64, BPF_OP(code), dst,
						  src, dstk, sstk, &prog,
						  bpf_prog->aux);
				break;
			case BPF_K:
				emit_ia32_alu_i64(is64, BPF_OP(code), dst,
						  imm32, dstk, &prog,
						  bpf_prog->aux);
				break;
			}
			break;
		case BPF_ALU | BPF_MUL | BPF_K:
		case BPF_ALU | BPF_MUL | BPF_X:
			switch (BPF_SRC(code)) {
			case BPF_X:
				emit_ia32_mul_r(dst_lo, src_lo, dstk,
						sstk, &prog);
				break;
			case BPF_K:
				/* mov ecx,imm32*/
				EMIT2_off32(0xC7, add_1reg(0xC0, IA32_ECX),
					    imm32);
				emit_ia32_mul_r(dst_lo, IA32_ECX, dstk,
						false, &prog);
				break;
			}
			if (!bpf_prog->aux->verifier_zext)
				emit_ia32_mov_i(dst_hi, 0, dstk, &prog);
			break;
		case BPF_ALU | BPF_LSH | BPF_X:
		case BPF_ALU | BPF_RSH | BPF_X:
		case BPF_ALU | BPF_ARSH | BPF_K:
		case BPF_ALU | BPF_ARSH | BPF_X:
			switch (BPF_SRC(code)) {
			case BPF_X:
				emit_ia32_shift_r(BPF_OP(code), dst_lo, src_lo,
						  dstk, sstk, &prog);
				break;
			case BPF_K:
				/* mov ecx,imm32*/
				EMIT2_off32(0xC7, add_1reg(0xC0, IA32_ECX),
					    imm32);
				emit_ia32_shift_r(BPF_OP(code), dst_lo,
						  IA32_ECX, dstk, false,
						  &prog);
				break;
			}
			if (!bpf_prog->aux->verifier_zext)
				emit_ia32_mov_i(dst_hi, 0, dstk, &prog);
			break;
		/* dst = dst / src(imm) */
		/* dst = dst % src(imm) */
		case BPF_ALU | BPF_DIV | BPF_K:
		case BPF_ALU | BPF_DIV | BPF_X:
		case BPF_ALU | BPF_MOD | BPF_K:
		case BPF_ALU | BPF_MOD | BPF_X:
			switch (BPF_SRC(code)) {
			case BPF_X:
				emit_ia32_div_mod_r(BPF_OP(code), dst_lo,
						    src_lo, dstk, sstk, &prog);
				break;
			case BPF_K:
				/* mov ecx,imm32*/
				EMIT2_off32(0xC7, add_1reg(0xC0, IA32_ECX),
					    imm32);
				emit_ia32_div_mod_r(BPF_OP(code), dst_lo,
						    IA32_ECX, dstk, false,
						    &prog);
				break;
			}
			if (!bpf_prog->aux->verifier_zext)
				emit_ia32_mov_i(dst_hi, 0, dstk, &prog);
			break;
		case BPF_ALU64 | BPF_DIV | BPF_K:
		case BPF_ALU64 | BPF_DIV | BPF_X:
		case BPF_ALU64 | BPF_MOD | BPF_K:
		case BPF_ALU64 | BPF_MOD | BPF_X:
			goto notyet;
		/* dst = dst >> imm */
		/* dst = dst << imm */
		case BPF_ALU | BPF_RSH | BPF_K:
		case BPF_ALU | BPF_LSH | BPF_K:
			if (unlikely(imm32 > 31))
				return -EINVAL;
			/* mov ecx,imm32*/
			EMIT2_off32(0xC7, add_1reg(0xC0, IA32_ECX), imm32);
			emit_ia32_shift_r(BPF_OP(code), dst_lo, IA32_ECX, dstk,
					  false, &prog);
			if (!bpf_prog->aux->verifier_zext)
				emit_ia32_mov_i(dst_hi, 0, dstk, &prog);
			break;
		/* dst = dst << imm */
		case BPF_ALU64 | BPF_LSH | BPF_K:
			if (unlikely(imm32 > 63))
				return -EINVAL;
			emit_ia32_lsh_i64(dst, imm32, dstk, &prog);
			break;
		/* dst = dst >> imm */
		case BPF_ALU64 | BPF_RSH | BPF_K:
			if (unlikely(imm32 > 63))
				return -EINVAL;
			emit_ia32_rsh_i64(dst, imm32, dstk, &prog);
			break;
		/* dst = dst << src */
		case BPF_ALU64 | BPF_LSH | BPF_X:
			emit_ia32_lsh_r64(dst, src, dstk, sstk, &prog);
			break;
		/* dst = dst >> src */
		case BPF_ALU64 | BPF_RSH | BPF_X:
			emit_ia32_rsh_r64(dst, src, dstk, sstk, &prog);
			break;
		/* dst = dst >> src (signed) */
		case BPF_ALU64 | BPF_ARSH | BPF_X:
			emit_ia32_arsh_r64(dst, src, dstk, sstk, &prog);
			break;
		/* dst = dst >> imm (signed) */
		case BPF_ALU64 | BPF_ARSH | BPF_K:
			if (unlikely(imm32 > 63))
				return -EINVAL;
			emit_ia32_arsh_i64(dst, imm32, dstk, &prog);
			break;
		/* dst = ~dst */
		case BPF_ALU | BPF_NEG:
			emit_ia32_alu_i(is64, false, BPF_OP(code),
					dst_lo, 0, dstk, &prog);
			if (!bpf_prog->aux->verifier_zext)
				emit_ia32_mov_i(dst_hi, 0, dstk, &prog);
			break;
		/* dst = ~dst (64 bit) */
		case BPF_ALU64 | BPF_NEG:
			emit_ia32_neg64(dst, dstk, &prog);
			break;
		/* dst = dst * src/imm */
		case BPF_ALU64 | BPF_MUL | BPF_X:
		case BPF_ALU64 | BPF_MUL | BPF_K:
			switch (BPF_SRC(code)) {
			case BPF_X:
				emit_ia32_mul_r64(dst, src, dstk, sstk, &prog);
				break;
			case BPF_K:
				emit_ia32_mul_i64(dst, imm32, dstk, &prog);
				break;
			}
			break;
		/* dst = htole(dst) */
		case BPF_ALU | BPF_END | BPF_FROM_LE:
			emit_ia32_to_le_r64(dst, imm32, dstk, &prog,
					    bpf_prog->aux);
			break;
		/* dst = htobe(dst) */
		case BPF_ALU | BPF_END | BPF_FROM_BE:
			emit_ia32_to_be_r64(dst, imm32, dstk, &prog,
					    bpf_prog->aux);
			break;
		/* dst = imm64 */
		case BPF_LD | BPF_IMM | BPF_DW: {
			s32 hi, lo = imm32;

			hi = insn[1].imm;
			emit_ia32_mov_i(dst_lo, lo, dstk, &prog);
			emit_ia32_mov_i(dst_hi, hi, dstk, &prog);
			insn++;
			i++;
			break;
		}
		/* ST: *(u8*)(dst_reg + off) = imm */
		case BPF_ST | BPF_MEM | BPF_H:
		case BPF_ST | BPF_MEM | BPF_B:
		case BPF_ST | BPF_MEM | BPF_W:
		case BPF_ST | BPF_MEM | BPF_DW:
			if (dstk)
				/* mov eax,dword ptr [ebp+off] */
				EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX),
				      STACK_VAR(dst_lo));
			else
				/* mov eax,dst_lo */
				EMIT2(0x8B, add_2reg(0xC0, dst_lo, IA32_EAX));

			switch (BPF_SIZE(code)) {
			case BPF_B:
				EMIT(0xC6, 1); break;
			case BPF_H:
				EMIT2(0x66, 0xC7); break;
			case BPF_W:
			case BPF_DW:
				EMIT(0xC7, 1); break;
			}

			if (is_imm8(insn->off))
				EMIT2(add_1reg(0x40, IA32_EAX), insn->off);
			else
				EMIT1_off32(add_1reg(0x80, IA32_EAX),
					    insn->off);
			EMIT(imm32, bpf_size_to_x86_bytes(BPF_SIZE(code)));

			if (BPF_SIZE(code) == BPF_DW) {
				u32 hi;

				hi = imm32 & (1<<31) ? (u32)~0 : 0;
				EMIT2_off32(0xC7, add_1reg(0x80, IA32_EAX),
					    insn->off + 4);
				EMIT(hi, 4);
			}
			break;

		/* STX: *(u8*)(dst_reg + off) = src_reg */
		case BPF_STX | BPF_MEM | BPF_B:
		case BPF_STX | BPF_MEM | BPF_H:
		case BPF_STX | BPF_MEM | BPF_W:
		case BPF_STX | BPF_MEM | BPF_DW:
			if (dstk)
				/* mov eax,dword ptr [ebp+off] */
				EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX),
				      STACK_VAR(dst_lo));
			else
				/* mov eax,dst_lo */
				EMIT2(0x8B, add_2reg(0xC0, dst_lo, IA32_EAX));

			if (sstk)
				/* mov edx,dword ptr [ebp+off] */
				EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EDX),
				      STACK_VAR(src_lo));
			else
				/* mov edx,src_lo */
				EMIT2(0x8B, add_2reg(0xC0, src_lo, IA32_EDX));

			switch (BPF_SIZE(code)) {
			case BPF_B:
				EMIT(0x88, 1); break;
			case BPF_H:
				EMIT2(0x66, 0x89); break;
			case BPF_W:
			case BPF_DW:
				EMIT(0x89, 1); break;
			}

			if (is_imm8(insn->off))
				EMIT2(add_2reg(0x40, IA32_EAX, IA32_EDX),
				      insn->off);
			else
				EMIT1_off32(add_2reg(0x80, IA32_EAX, IA32_EDX),
					    insn->off);

			if (BPF_SIZE(code) == BPF_DW) {
				if (sstk)
					/* mov edi,dword ptr [ebp+off] */
					EMIT3(0x8B, add_2reg(0x40, IA32_EBP,
							     IA32_EDX),
					      STACK_VAR(src_hi));
				else
					/* mov edi,src_hi */
					EMIT2(0x8B, add_2reg(0xC0, src_hi,
							     IA32_EDX));
				EMIT1(0x89);
				if (is_imm8(insn->off + 4)) {
					EMIT2(add_2reg(0x40, IA32_EAX,
						       IA32_EDX),
					      insn->off + 4);
				} else {
					EMIT1(add_2reg(0x80, IA32_EAX,
						       IA32_EDX));
					EMIT(insn->off + 4, 4);
				}
			}
			break;

		/* LDX: dst_reg = *(u8*)(src_reg + off) */
		case BPF_LDX | BPF_MEM | BPF_B:
		case BPF_LDX | BPF_MEM | BPF_H:
		case BPF_LDX | BPF_MEM | BPF_W:
		case BPF_LDX | BPF_MEM | BPF_DW:
			if (sstk)
				/* mov eax,dword ptr [ebp+off] */
				EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX),
				      STACK_VAR(src_lo));
			else
				/* mov eax,dword ptr [ebp+off] */
				EMIT2(0x8B, add_2reg(0xC0, src_lo, IA32_EAX));

			switch (BPF_SIZE(code)) {
			case BPF_B:
				EMIT2(0x0F, 0xB6); break;
			case BPF_H:
				EMIT2(0x0F, 0xB7); break;
			case BPF_W:
			case BPF_DW:
				EMIT(0x8B, 1); break;
			}

			if (is_imm8(insn->off))
				EMIT2(add_2reg(0x40, IA32_EAX, IA32_EDX),
				      insn->off);
			else
				EMIT1_off32(add_2reg(0x80, IA32_EAX, IA32_EDX),
					    insn->off);

			if (dstk)
				/* mov dword ptr [ebp+off],edx */
				EMIT3(0x89, add_2reg(0x40, IA32_EBP, IA32_EDX),
				      STACK_VAR(dst_lo));
			else
				/* mov dst_lo,edx */
				EMIT2(0x89, add_2reg(0xC0, dst_lo, IA32_EDX));
			switch (BPF_SIZE(code)) {
			case BPF_B:
			case BPF_H:
			case BPF_W:
				if (bpf_prog->aux->verifier_zext)
					break;
				if (dstk) {
					EMIT3(0xC7, add_1reg(0x40, IA32_EBP),
					      STACK_VAR(dst_hi));
					EMIT(0x0, 4);
				} else {
					/* xor dst_hi,dst_hi */
					EMIT2(0x33,
					      add_2reg(0xC0, dst_hi, dst_hi));
				}
				break;
			case BPF_DW:
				EMIT2_off32(0x8B,
					    add_2reg(0x80, IA32_EAX, IA32_EDX),
					    insn->off + 4);
				if (dstk)
					EMIT3(0x89,
					      add_2reg(0x40, IA32_EBP,
						       IA32_EDX),
					      STACK_VAR(dst_hi));
				else
					EMIT2(0x89,
					      add_2reg(0xC0, dst_hi, IA32_EDX));
				break;
			default:
				break;
			}
			break;
		/* call */
		case BPF_JMP | BPF_CALL:
		{
			const u8 *r1 = bpf2ia32[BPF_REG_1];
			const u8 *r2 = bpf2ia32[BPF_REG_2];
			const u8 *r3 = bpf2ia32[BPF_REG_3];
			const u8 *r4 = bpf2ia32[BPF_REG_4];
			const u8 *r5 = bpf2ia32[BPF_REG_5];

			if (insn->src_reg == BPF_PSEUDO_CALL)
				goto notyet;

			func = (u8 *) __bpf_call_base + imm32;
			jmp_offset = func - (image + addrs[i]);

			if (!imm32 || !is_simm32(jmp_offset)) {
				pr_err("unsupported BPF func %d addr %p image %p\n",
				       imm32, func, image);
				return -EINVAL;
			}

			/* mov eax,dword ptr [ebp+off] */
			EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX),
			      STACK_VAR(r1[0]));
			/* mov edx,dword ptr [ebp+off] */
			EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EDX),
			      STACK_VAR(r1[1]));

			emit_push_r64(r5, &prog);
			emit_push_r64(r4, &prog);
			emit_push_r64(r3, &prog);
			emit_push_r64(r2, &prog);

			EMIT1_off32(0xE8, jmp_offset + 9);

			/* mov dword ptr [ebp+off],eax */
			EMIT3(0x89, add_2reg(0x40, IA32_EBP, IA32_EAX),
			      STACK_VAR(r0[0]));
			/* mov dword ptr [ebp+off],edx */
			EMIT3(0x89, add_2reg(0x40, IA32_EBP, IA32_EDX),
			      STACK_VAR(r0[1]));

			/* add esp,32 */
			EMIT3(0x83, add_1reg(0xC0, IA32_ESP), 32);
			break;
		}
		case BPF_JMP | BPF_TAIL_CALL:
			emit_bpf_tail_call(&prog);
			break;

		/* cond jump */
		case BPF_JMP | BPF_JEQ | BPF_X:
		case BPF_JMP | BPF_JNE | BPF_X:
		case BPF_JMP | BPF_JGT | BPF_X:
		case BPF_JMP | BPF_JLT | BPF_X:
		case BPF_JMP | BPF_JGE | BPF_X:
		case BPF_JMP | BPF_JLE | BPF_X:
		case BPF_JMP32 | BPF_JEQ | BPF_X:
		case BPF_JMP32 | BPF_JNE | BPF_X:
		case BPF_JMP32 | BPF_JGT | BPF_X:
		case BPF_JMP32 | BPF_JLT | BPF_X:
		case BPF_JMP32 | BPF_JGE | BPF_X:
		case BPF_JMP32 | BPF_JLE | BPF_X:
		case BPF_JMP32 | BPF_JSGT | BPF_X:
		case BPF_JMP32 | BPF_JSLE | BPF_X:
		case BPF_JMP32 | BPF_JSLT | BPF_X:
		case BPF_JMP32 | BPF_JSGE | BPF_X: {
			bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP;
			u8 dreg_lo = dstk ? IA32_EAX : dst_lo;
			u8 dreg_hi = dstk ? IA32_EDX : dst_hi;
			u8 sreg_lo = sstk ? IA32_ECX : src_lo;
			u8 sreg_hi = sstk ? IA32_EBX : src_hi;

			if (dstk) {
				EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX),
				      STACK_VAR(dst_lo));
				if (is_jmp64)
					EMIT3(0x8B,
					      add_2reg(0x40, IA32_EBP,
						       IA32_EDX),
					      STACK_VAR(dst_hi));
			}

			if (sstk) {
				EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_ECX),
				      STACK_VAR(src_lo));
				if (is_jmp64)
					EMIT3(0x8B,
					      add_2reg(0x40, IA32_EBP,
						       IA32_EBX),
					      STACK_VAR(src_hi));
			}

			if (is_jmp64) {
				/* cmp dreg_hi,sreg_hi */
				EMIT2(0x39, add_2reg(0xC0, dreg_hi, sreg_hi));
				EMIT2(IA32_JNE, 2);
			}
			/* cmp dreg_lo,sreg_lo */
			EMIT2(0x39, add_2reg(0xC0, dreg_lo, sreg_lo));
			goto emit_cond_jmp;
		}
		case BPF_JMP | BPF_JSGT | BPF_X:
		case BPF_JMP | BPF_JSLE | BPF_X:
		case BPF_JMP | BPF_JSLT | BPF_X:
		case BPF_JMP | BPF_JSGE | BPF_X: {
			u8 dreg_lo = dstk ? IA32_EAX : dst_lo;
			u8 dreg_hi = dstk ? IA32_EDX : dst_hi;
			u8 sreg_lo = sstk ? IA32_ECX : src_lo;
			u8 sreg_hi = sstk ? IA32_EBX : src_hi;

			if (dstk) {
				EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX),
				      STACK_VAR(dst_lo));
				EMIT3(0x8B,
				      add_2reg(0x40, IA32_EBP,
					       IA32_EDX),
				      STACK_VAR(dst_hi));
			}

			if (sstk) {
				EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_ECX),
				      STACK_VAR(src_lo));
				EMIT3(0x8B,
				      add_2reg(0x40, IA32_EBP,
					       IA32_EBX),
				      STACK_VAR(src_hi));
			}

			/* cmp dreg_hi,sreg_hi */
			EMIT2(0x39, add_2reg(0xC0, dreg_hi, sreg_hi));
			EMIT2(IA32_JNE, 10);
			/* cmp dreg_lo,sreg_lo */
			EMIT2(0x39, add_2reg(0xC0, dreg_lo, sreg_lo));
			goto emit_cond_jmp_signed;
		}
		case BPF_JMP | BPF_JSET | BPF_X:
		case BPF_JMP32 | BPF_JSET | BPF_X: {
			bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP;
			u8 dreg_lo = IA32_EAX;
			u8 dreg_hi = IA32_EDX;
			u8 sreg_lo = sstk ? IA32_ECX : src_lo;
			u8 sreg_hi = sstk ? IA32_EBX : src_hi;

			if (dstk) {
				EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX),
				      STACK_VAR(dst_lo));
				if (is_jmp64)
					EMIT3(0x8B,
					      add_2reg(0x40, IA32_EBP,
						       IA32_EDX),
					      STACK_VAR(dst_hi));
			} else {
				/* mov dreg_lo,dst_lo */
				EMIT2(0x89, add_2reg(0xC0, dreg_lo, dst_lo));
				if (is_jmp64)
					/* mov dreg_hi,dst_hi */
					EMIT2(0x89,
					      add_2reg(0xC0, dreg_hi, dst_hi));
			}

			if (sstk) {
				EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_ECX),
				      STACK_VAR(src_lo));
				if (is_jmp64)
					EMIT3(0x8B,
					      add_2reg(0x40, IA32_EBP,
						       IA32_EBX),
					      STACK_VAR(src_hi));
			}
			/* and dreg_lo,sreg_lo */
			EMIT2(0x23, add_2reg(0xC0, sreg_lo, dreg_lo));
			if (is_jmp64) {
				/* and dreg_hi,sreg_hi */
				EMIT2(0x23, add_2reg(0xC0, sreg_hi, dreg_hi));
				/* or dreg_lo,dreg_hi */
				EMIT2(0x09, add_2reg(0xC0, dreg_lo, dreg_hi));
			}
			goto emit_cond_jmp;
		}
		case BPF_JMP | BPF_JSET | BPF_K:
		case BPF_JMP32 | BPF_JSET | BPF_K: {
			bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP;
			u8 dreg_lo = IA32_EAX;
			u8 dreg_hi = IA32_EDX;
			u8 sreg_lo = IA32_ECX;
			u8 sreg_hi = IA32_EBX;
			u32 hi;

			if (dstk) {
				EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX),
				      STACK_VAR(dst_lo));
				if (is_jmp64)
					EMIT3(0x8B,
					      add_2reg(0x40, IA32_EBP,
						       IA32_EDX),
					      STACK_VAR(dst_hi));
			} else {
				/* mov dreg_lo,dst_lo */
				EMIT2(0x89, add_2reg(0xC0, dreg_lo, dst_lo));
				if (is_jmp64)
					/* mov dreg_hi,dst_hi */
					EMIT2(0x89,
					      add_2reg(0xC0, dreg_hi, dst_hi));
			}

			/* mov ecx,imm32 */
			EMIT2_off32(0xC7, add_1reg(0xC0, sreg_lo), imm32);

			/* and dreg_lo,sreg_lo */
			EMIT2(0x23, add_2reg(0xC0, sreg_lo, dreg_lo));
			if (is_jmp64) {
				hi = imm32 & (1 << 31) ? (u32)~0 : 0;
				/* mov ebx,imm32 */
				EMIT2_off32(0xC7, add_1reg(0xC0, sreg_hi), hi);
				/* and dreg_hi,sreg_hi */
				EMIT2(0x23, add_2reg(0xC0, sreg_hi, dreg_hi));
				/* or dreg_lo,dreg_hi */
				EMIT2(0x09, add_2reg(0xC0, dreg_lo, dreg_hi));
			}
			goto emit_cond_jmp;
		}
		case BPF_JMP | BPF_JEQ | BPF_K:
		case BPF_JMP | BPF_JNE | BPF_K:
		case BPF_JMP | BPF_JGT | BPF_K:
		case BPF_JMP | BPF_JLT | BPF_K:
		case BPF_JMP | BPF_JGE | BPF_K:
		case BPF_JMP | BPF_JLE | BPF_K:
		case BPF_JMP32 | BPF_JEQ | BPF_K:
		case BPF_JMP32 | BPF_JNE | BPF_K:
		case BPF_JMP32 | BPF_JGT | BPF_K:
		case BPF_JMP32 | BPF_JLT | BPF_K:
		case BPF_JMP32 | BPF_JGE | BPF_K:
		case BPF_JMP32 | BPF_JLE | BPF_K:
		case BPF_JMP32 | BPF_JSGT | BPF_K:
		case BPF_JMP32 | BPF_JSLE | BPF_K:
		case BPF_JMP32 | BPF_JSLT | BPF_K:
		case BPF_JMP32 | BPF_JSGE | BPF_K: {
			bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP;
			u8 dreg_lo = dstk ? IA32_EAX : dst_lo;
			u8 dreg_hi = dstk ? IA32_EDX : dst_hi;
			u8 sreg_lo = IA32_ECX;
			u8 sreg_hi = IA32_EBX;
			u32 hi;

			if (dstk) {
				EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX),
				      STACK_VAR(dst_lo));
				if (is_jmp64)
					EMIT3(0x8B,
					      add_2reg(0x40, IA32_EBP,
						       IA32_EDX),
					      STACK_VAR(dst_hi));
			}

			/* mov ecx,imm32 */
			EMIT2_off32(0xC7, add_1reg(0xC0, IA32_ECX), imm32);
			if (is_jmp64) {
				hi = imm32 & (1 << 31) ? (u32)~0 : 0;
				/* mov ebx,imm32 */
				EMIT2_off32(0xC7, add_1reg(0xC0, IA32_EBX), hi);
				/* cmp dreg_hi,sreg_hi */
				EMIT2(0x39, add_2reg(0xC0, dreg_hi, sreg_hi));
				EMIT2(IA32_JNE, 2);
			}
			/* cmp dreg_lo,sreg_lo */
			EMIT2(0x39, add_2reg(0xC0, dreg_lo, sreg_lo));

emit_cond_jmp:		jmp_cond = get_cond_jmp_opcode(BPF_OP(code), false);
			if (jmp_cond == COND_JMP_OPCODE_INVALID)
				return -EFAULT;
			jmp_offset = addrs[i + insn->off] - addrs[i];
			if (is_imm8(jmp_offset)) {
				EMIT2(jmp_cond, jmp_offset);
			} else if (is_simm32(jmp_offset)) {
				EMIT2_off32(0x0F, jmp_cond + 0x10, jmp_offset);
			} else {
				pr_err("cond_jmp gen bug %llx\n", jmp_offset);
				return -EFAULT;
			}
			break;
		}
		case BPF_JMP | BPF_JSGT | BPF_K:
		case BPF_JMP | BPF_JSLE | BPF_K:
		case BPF_JMP | BPF_JSLT | BPF_K:
		case BPF_JMP | BPF_JSGE | BPF_K: {
			u8 dreg_lo = dstk ? IA32_EAX : dst_lo;
			u8 dreg_hi = dstk ? IA32_EDX : dst_hi;
			u8 sreg_lo = IA32_ECX;
			u8 sreg_hi = IA32_EBX;
			u32 hi;

			if (dstk) {
				EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX),
				      STACK_VAR(dst_lo));
				EMIT3(0x8B,
				      add_2reg(0x40, IA32_EBP,
					       IA32_EDX),
				      STACK_VAR(dst_hi));
			}

			/* mov ecx,imm32 */
			EMIT2_off32(0xC7, add_1reg(0xC0, IA32_ECX), imm32);
			hi = imm32 & (1 << 31) ? (u32)~0 : 0;
			/* mov ebx,imm32 */
			EMIT2_off32(0xC7, add_1reg(0xC0, IA32_EBX), hi);
			/* cmp dreg_hi,sreg_hi */
			EMIT2(0x39, add_2reg(0xC0, dreg_hi, sreg_hi));
			EMIT2(IA32_JNE, 10);
			/* cmp dreg_lo,sreg_lo */
			EMIT2(0x39, add_2reg(0xC0, dreg_lo, sreg_lo));

			/*
			 * For simplicity of branch offset computation,
			 * let's use fixed jump coding here.
			 */
emit_cond_jmp_signed:	/* Check the condition for low 32-bit comparison */
			jmp_cond = get_cond_jmp_opcode(BPF_OP(code), true);
			if (jmp_cond == COND_JMP_OPCODE_INVALID)
				return -EFAULT;
			jmp_offset = addrs[i + insn->off] - addrs[i] + 8;
			if (is_simm32(jmp_offset)) {
				EMIT2_off32(0x0F, jmp_cond + 0x10, jmp_offset);
			} else {
				pr_err("cond_jmp gen bug %llx\n", jmp_offset);
				return -EFAULT;
			}
			EMIT2(0xEB, 6);

			/* Check the condition for high 32-bit comparison */
			jmp_cond = get_cond_jmp_opcode(BPF_OP(code), false);
			if (jmp_cond == COND_JMP_OPCODE_INVALID)
				return -EFAULT;
			jmp_offset = addrs[i + insn->off] - addrs[i];
			if (is_simm32(jmp_offset)) {
				EMIT2_off32(0x0F, jmp_cond + 0x10, jmp_offset);
			} else {
				pr_err("cond_jmp gen bug %llx\n", jmp_offset);
				return -EFAULT;
			}
			break;
		}
		case BPF_JMP | BPF_JA:
			if (insn->off == -1)
				/* -1 jmp instructions will always jump
				 * backwards two bytes. Explicitly handling
				 * this case avoids wasting too many passes
				 * when there are long sequences of replaced
				 * dead code.
				 */
				jmp_offset = -2;
			else
				jmp_offset = addrs[i + insn->off] - addrs[i];

			if (!jmp_offset)
				/* Optimize out nop jumps */
				break;
emit_jmp:
			if (is_imm8(jmp_offset)) {
				EMIT2(0xEB, jmp_offset);
			} else if (is_simm32(jmp_offset)) {
				EMIT1_off32(0xE9, jmp_offset);
			} else {
				pr_err("jmp gen bug %llx\n", jmp_offset);
				return -EFAULT;
			}
			break;
		/* STX XADD: lock *(u32 *)(dst + off) += src */
		case BPF_STX | BPF_XADD | BPF_W:
		/* STX XADD: lock *(u64 *)(dst + off) += src */
		case BPF_STX | BPF_XADD | BPF_DW:
			goto notyet;
		case BPF_JMP | BPF_EXIT:
			if (seen_exit) {
				jmp_offset = ctx->cleanup_addr - addrs[i];
				goto emit_jmp;
			}
			seen_exit = true;
			/* Update cleanup_addr */
			ctx->cleanup_addr = proglen;
			emit_epilogue(&prog, bpf_prog->aux->stack_depth);
			break;
notyet:
			pr_info_once("*** NOT YET: opcode %02x ***\n", code);
			return -EFAULT;
		default:
			/*
			 * This error will be seen if new instruction was added
			 * to interpreter, but not to JIT or if there is junk in
			 * bpf_prog
			 */
			pr_err("bpf_jit: unknown opcode %02x\n", code);
			return -EINVAL;
		}

		ilen = prog - temp;
		if (ilen > BPF_MAX_INSN_SIZE) {
			pr_err("bpf_jit: fatal insn size error\n");
			return -EFAULT;
		}

		if (image) {
			if (unlikely(proglen + ilen > oldproglen)) {
				pr_err("bpf_jit: fatal error\n");
				return -EFAULT;
			}
			memcpy(image + proglen, temp, ilen);
		}
		proglen += ilen;
		addrs[i] = proglen;
		prog = temp;
	}
	return proglen;
}