@@ -143,14 +143,17 @@ static inline void emit_addr_mov_i64(const int reg, const u64 val,
143
143
}
144
144
}
145
145
146
- static inline int bpf2a64_offset (int bpf_to , int bpf_from ,
146
+ static inline int bpf2a64_offset (int bpf_insn , int off ,
147
147
const struct jit_ctx * ctx )
148
148
{
149
- int to = ctx -> offset [bpf_to ];
150
- /* -1 to account for the Branch instruction */
151
- int from = ctx -> offset [bpf_from ] - 1 ;
152
-
153
- return to - from ;
149
+ /* BPF JMP offset is relative to the next instruction */
150
+ bpf_insn ++ ;
151
+ /*
152
+ * Whereas arm64 branch instructions encode the offset
153
+ * from the branch itself, so we must subtract 1 from the
154
+ * instruction offset.
155
+ */
156
+ return ctx -> offset [bpf_insn + off ] - (ctx -> offset [bpf_insn ] - 1 );
154
157
}
155
158
156
159
static void jit_fill_hole (void * area , unsigned int size )
@@ -642,7 +645,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
642
645
643
646
/* JUMP off */
644
647
case BPF_JMP | BPF_JA :
645
- jmp_offset = bpf2a64_offset (i + off , i , ctx );
648
+ jmp_offset = bpf2a64_offset (i , off , ctx );
646
649
check_imm26 (jmp_offset );
647
650
emit (A64_B (jmp_offset ), ctx );
648
651
break ;
@@ -669,7 +672,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
669
672
case BPF_JMP32 | BPF_JSLE | BPF_X :
670
673
emit (A64_CMP (is64 , dst , src ), ctx );
671
674
emit_cond_jmp :
672
- jmp_offset = bpf2a64_offset (i + off , i , ctx );
675
+ jmp_offset = bpf2a64_offset (i , off , ctx );
673
676
check_imm19 (jmp_offset );
674
677
switch (BPF_OP (code )) {
675
678
case BPF_JEQ :
@@ -908,22 +911,38 @@ static int build_body(struct jit_ctx *ctx, bool extra_pass)
908
911
const struct bpf_prog * prog = ctx -> prog ;
909
912
int i ;
910
913
914
+ /*
915
+ * - offset[0] offset of the end of prologue,
916
+ * start of the 1st instruction.
917
+ * - offset[1] - offset of the end of 1st instruction,
918
+ * start of the 2nd instruction
919
+ * [....]
920
+ * - offset[3] - offset of the end of 3rd instruction,
921
+ * start of 4th instruction
922
+ */
911
923
for (i = 0 ; i < prog -> len ; i ++ ) {
912
924
const struct bpf_insn * insn = & prog -> insnsi [i ];
913
925
int ret ;
914
926
927
+ if (ctx -> image == NULL )
928
+ ctx -> offset [i ] = ctx -> idx ;
915
929
ret = build_insn (insn , ctx , extra_pass );
916
930
if (ret > 0 ) {
917
931
i ++ ;
918
932
if (ctx -> image == NULL )
919
933
ctx -> offset [i ] = ctx -> idx ;
920
934
continue ;
921
935
}
922
- if (ctx -> image == NULL )
923
- ctx -> offset [i ] = ctx -> idx ;
924
936
if (ret )
925
937
return ret ;
926
938
}
939
+ /*
940
+ * offset is allocated with prog->len + 1 so fill in
941
+ * the last element with the offset after the last
942
+ * instruction (end of program)
943
+ */
944
+ if (ctx -> image == NULL )
945
+ ctx -> offset [i ] = ctx -> idx ;
927
946
928
947
return 0 ;
929
948
}
@@ -1002,7 +1021,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
1002
1021
memset (& ctx , 0 , sizeof (ctx ));
1003
1022
ctx .prog = prog ;
1004
1023
1005
- ctx .offset = kcalloc (prog -> len , sizeof (int ), GFP_KERNEL );
1024
+ ctx .offset = kcalloc (prog -> len + 1 , sizeof (int ), GFP_KERNEL );
1006
1025
if (ctx .offset == NULL ) {
1007
1026
prog = orig_prog ;
1008
1027
goto out_off ;
@@ -1089,7 +1108,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
1089
1108
prog -> jited_len = prog_size ;
1090
1109
1091
1110
if (!prog -> is_func || extra_pass ) {
1092
- bpf_prog_fill_jited_linfo (prog , ctx .offset );
1111
+ bpf_prog_fill_jited_linfo (prog , ctx .offset + 1 );
1093
1112
out_off :
1094
1113
kfree (ctx .offset );
1095
1114
kfree (jit_data );
0 commit comments