arm64/bpf: use movn/movk/movk sequence to generate kernel addresses
On arm64, all executable code is guaranteed to reside in the vmalloc space (or the module space), and so jump targets will only use 48 bits at most, and the remaining bits are guaranteed to be 0x1. This means we can generate an immediate jump address using a sequence of one MOVN (move wide negated) and two MOVK instructions, where the first one sets the lower 16 bits but also sets all top bits to 0x1. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Acked-by: Will Deacon <will.deacon@arm.com> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
parent
93029d7d40
commit
cc2b8ed136
@ -134,10 +134,9 @@ static inline void emit_a64_mov_i64(const int reg, const u64 val,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is an unoptimized 64 immediate emission used for BPF to BPF call
|
* Kernel addresses in the vmalloc space use at most 48 bits, and the
|
||||||
* addresses. It will always do a full 64 bit decomposition as otherwise
|
* remaining bits are guaranteed to be 0x1. So we can compose the address
|
||||||
* more complexity in the last extra pass is required since we previously
|
* with a fixed length movn/movk/movk sequence.
|
||||||
* reserved 4 instructions for the address.
|
|
||||||
*/
|
*/
|
||||||
static inline void emit_addr_mov_i64(const int reg, const u64 val,
|
static inline void emit_addr_mov_i64(const int reg, const u64 val,
|
||||||
struct jit_ctx *ctx)
|
struct jit_ctx *ctx)
|
||||||
@ -145,8 +144,8 @@ static inline void emit_addr_mov_i64(const int reg, const u64 val,
|
|||||||
u64 tmp = val;
|
u64 tmp = val;
|
||||||
int shift = 0;
|
int shift = 0;
|
||||||
|
|
||||||
emit(A64_MOVZ(1, reg, tmp & 0xffff, shift), ctx);
|
emit(A64_MOVN(1, reg, ~tmp & 0xffff, shift), ctx);
|
||||||
for (;shift < 48;) {
|
while (shift < 32) {
|
||||||
tmp >>= 16;
|
tmp >>= 16;
|
||||||
shift += 16;
|
shift += 16;
|
||||||
emit(A64_MOVK(1, reg, tmp & 0xffff, shift), ctx);
|
emit(A64_MOVK(1, reg, tmp & 0xffff, shift), ctx);
|
||||||
@ -634,11 +633,7 @@ emit_cond_jmp:
|
|||||||
&func_addr, &func_addr_fixed);
|
&func_addr, &func_addr_fixed);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
if (func_addr_fixed)
|
emit_addr_mov_i64(tmp, func_addr, ctx);
|
||||||
/* We can use optimized emission here. */
|
|
||||||
emit_a64_mov_i64(tmp, func_addr, ctx);
|
|
||||||
else
|
|
||||||
emit_addr_mov_i64(tmp, func_addr, ctx);
|
|
||||||
emit(A64_BLR(tmp), ctx);
|
emit(A64_BLR(tmp), ctx);
|
||||||
emit(A64_MOV(1, r0, A64_R(0)), ctx);
|
emit(A64_MOV(1, r0, A64_R(0)), ctx);
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user