diff options
Diffstat (limited to 'arch/x86/net/bpf_jit_comp.c')
| -rw-r--r-- | arch/x86/net/bpf_jit_comp.c | 35 | 
1 files changed, 34 insertions, 1 deletions
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 987514396c1e..ddeff4844a10 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -559,6 +559,13 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,  				if (is_ereg(dst_reg))  					EMIT1(0x41);  				EMIT3(0xC1, add_1reg(0xC8, dst_reg), 8); + +				/* emit 'movzwl eax, ax' */ +				if (is_ereg(dst_reg)) +					EMIT3(0x45, 0x0F, 0xB7); +				else +					EMIT2(0x0F, 0xB7); +				EMIT1(add_2reg(0xC0, dst_reg, dst_reg));  				break;  			case 32:  				/* emit 'bswap eax' to swap lower 4 bytes */ @@ -577,6 +584,27 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,  			break;  		case BPF_ALU | BPF_END | BPF_FROM_LE: +			switch (imm32) { +			case 16: +				/* emit 'movzwl eax, ax' to zero extend 16-bit +				 * into 64 bit +				 */ +				if (is_ereg(dst_reg)) +					EMIT3(0x45, 0x0F, 0xB7); +				else +					EMIT2(0x0F, 0xB7); +				EMIT1(add_2reg(0xC0, dst_reg, dst_reg)); +				break; +			case 32: +				/* emit 'mov eax, eax' to clear upper 32-bits */ +				if (is_ereg(dst_reg)) +					EMIT1(0x45); +				EMIT2(0x89, add_2reg(0xC0, dst_reg, dst_reg)); +				break; +			case 64: +				/* nop */ +				break; +			}  			break;  			/* ST: *(u8*)(dst_reg + off) = imm */ @@ -938,7 +966,12 @@ void bpf_int_jit_compile(struct bpf_prog *prog)  	}  	ctx.cleanup_addr = proglen; -	for (pass = 0; pass < 10; pass++) { +	/* JITed image shrinks with every pass and the loop iterates +	 * until the image stops shrinking. Very large bpf programs +	 * may converge on the last pass. In such case do one more +	 * pass to emit the final image +	 */ +	for (pass = 0; pass < 10 || image; pass++) {  		proglen = do_jit(prog, addrs, image, oldproglen, &ctx);  		if (proglen <= 0) {  			image = NULL;  |