diff options
Diffstat (limited to 'arch/arm/net')
| -rw-r--r-- | arch/arm/net/bpf_jit_32.c | 52 | 
1 files changed, 34 insertions, 18 deletions
| diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index cc29869d12a3..bf85d6db4931 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -929,7 +929,11 @@ static inline void emit_a32_rsh_i64(const s8 dst[],  	rd = arm_bpf_get_reg64(dst, tmp, ctx);  	/* Do LSR operation */ -	if (val < 32) { +	if (val == 0) { +		/* An immediate value of 0 encodes a shift amount of 32 +		 * for LSR. To shift by 0, don't do anything. +		 */ +	} else if (val < 32) {  		emit(ARM_MOV_SI(tmp2[1], rd[1], SRTYPE_LSR, val), ctx);  		emit(ARM_ORR_SI(rd[1], tmp2[1], rd[0], SRTYPE_ASL, 32 - val), ctx);  		emit(ARM_MOV_SI(rd[0], rd[0], SRTYPE_LSR, val), ctx); @@ -955,7 +959,11 @@ static inline void emit_a32_arsh_i64(const s8 dst[],  	rd = arm_bpf_get_reg64(dst, tmp, ctx);  	/* Do ARSH operation */ -	if (val < 32) { +	if (val == 0) { +		/* An immediate value of 0 encodes a shift amount of 32 +		 * for ASR. To shift by 0, don't do anything. +		 */ +	} else if (val < 32) {  		emit(ARM_MOV_SI(tmp2[1], rd[1], SRTYPE_LSR, val), ctx);  		emit(ARM_ORR_SI(rd[1], tmp2[1], rd[0], SRTYPE_ASL, 32 - val), ctx);  		emit(ARM_MOV_SI(rd[0], rd[0], SRTYPE_ASR, val), ctx); @@ -992,21 +1000,35 @@ static inline void emit_a32_mul_r64(const s8 dst[], const s8 src[],  	arm_bpf_put_reg32(dst_hi, rd[0], ctx);  } +static bool is_ldst_imm(s16 off, const u8 size) +{ +	s16 off_max = 0; + +	switch (size) { +	case BPF_B: +	case BPF_W: +		off_max = 0xfff; +		break; +	case BPF_H: +		off_max = 0xff; +		break; +	case BPF_DW: +		/* Need to make sure off+4 does not overflow. */ +		off_max = 0xfff - 4; +		break; +	} +	return -off_max <= off && off <= off_max; +} +  /* *(size *)(dst + off) = src */  static inline void emit_str_r(const s8 dst, const s8 src[], -			      s32 off, struct jit_ctx *ctx, const u8 sz){ +			      s16 off, struct jit_ctx *ctx, const u8 sz){  	const s8 *tmp = bpf2a32[TMP_REG_1]; -	s32 off_max;  	s8 rd;  	rd = arm_bpf_get_reg32(dst, tmp[1], ctx); -	if (sz == BPF_H) -		off_max = 0xff; -	else -		off_max = 0xfff; - -	if (off < 0 || off > off_max) { +	if (!is_ldst_imm(off, sz)) {  		emit_a32_mov_i(tmp[0], off, ctx);  		emit(ARM_ADD_R(tmp[0], tmp[0], rd), ctx);  		rd = tmp[0]; @@ -1035,18 +1057,12 @@ static inline void emit_str_r(const s8 dst, const s8 src[],  /* dst = *(size*)(src + off) */  static inline void emit_ldx_r(const s8 dst[], const s8 src, -			      s32 off, struct jit_ctx *ctx, const u8 sz){ +			      s16 off, struct jit_ctx *ctx, const u8 sz){  	const s8 *tmp = bpf2a32[TMP_REG_1];  	const s8 *rd = is_stacked(dst_lo) ? tmp : dst;  	s8 rm = src; -	s32 off_max; - -	if (sz == BPF_H) -		off_max = 0xff; -	else -		off_max = 0xfff; -	if (off < 0 || off > off_max) { +	if (!is_ldst_imm(off, sz)) {  		emit_a32_mov_i(tmp[0], off, ctx);  		emit(ARM_ADD_R(tmp[0], tmp[0], src), ctx);  		rm = tmp[0]; |