From: Sandipan Das <hidden> Date: 2018-05-24 06:57:05
[1] Support for bpf-to-bpf function calls in the powerpc64 JIT compiler.
[2] Provide a way for resolving function calls because of the way JITed
images are allocated in powerpc64.
[3] Fix to get JITed instruction dumps for multi-function programs from
the bpf system call.
[4] Fix for bpftool to show delimited multi-function JITed image dumps.
v4:
- Incorporate review comments from Jakub.
- Fix JSON output for bpftool.
v3:
- Change base tree tag to bpf-next.
- Incorporate review comments from Alexei, Daniel and Jakub.
- Make sure that the JITed image does not grow or shrink after
the last pass due to the way the instruction sequence used
to load a callee's address maybe optimized.
- Make additional changes to the bpf system call and bpftool to
make multi-function JITed dumps easier to correlate.
v2:
- Incorporate review comments from Jakub.
Sandipan Das (10):
bpf: support 64-bit offsets for bpf function calls
bpf: powerpc64: pad function address loads with NOPs
bpf: powerpc64: add JIT support for multi-function programs
bpf: get kernel symbol addresses via syscall
tools: bpf: sync bpf uapi header
tools: bpftool: resolve calls without using imm field
bpf: fix multi-function JITed dump obtained via syscall
bpf: get JITed image lengths of functions via syscall
tools: bpf: sync bpf uapi header
tools: bpftool: add delimiters to multi-function JITed dumps
arch/powerpc/net/bpf_jit_comp64.c | 110 ++++++++++++++++++++++++++++++--------
include/uapi/linux/bpf.h | 4 ++
kernel/bpf/syscall.c | 82 ++++++++++++++++++++++++++--
kernel/bpf/verifier.c | 22 +++++---
tools/bpf/bpftool/prog.c | 97 ++++++++++++++++++++++++++++++++-
tools/bpf/bpftool/xlated_dumper.c | 14 +++--
tools/bpf/bpftool/xlated_dumper.h | 3 ++
tools/include/uapi/linux/bpf.h | 4 ++
8 files changed, 301 insertions(+), 35 deletions(-)
--
2.14.3
From: Sandipan Das <hidden> Date: 2018-05-24 06:57:06
The imm field of a bpf instruction is a signed 32-bit integer.
For JITed bpf-to-bpf function calls, it holds the offset of the
start address of the callee's JITed image from __bpf_call_base.
For some architectures, such as powerpc64, this offset may be
as large as 64 bits and cannot be accomodated in the imm field
without truncation.
We resolve this by:
[1] Additionally using the auxiliary data of each function to
keep a list of start addresses of the JITed images for all
functions determined by the verifier.
[2] Retaining the subprog id inside the off field of the call
instructions and using it to index into the list mentioned
above and lookup the callee's address.
To make sure that the existing JIT compilers continue to work
without requiring changes, we keep the imm field as it is.
Signed-off-by: Sandipan Das <redacted>
---
kernel/bpf/verifier.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
@@ -5383,11 +5383,24 @@ static int jit_subprogs(struct bpf_verifier_env *env)insn->src_reg!=BPF_PSEUDO_CALL)continue;subprog=insn->off;-insn->off=0;insn->imm=(u64(*)(u64,u64,u64,u64,u64))func[subprog]->bpf_func-__bpf_call_base;}++/* we use the aux data to keep a list of the start addresses+*oftheJITedimagesforeachfunctionintheprogram+*+*forsomearchitectures,suchaspowerpc64,theimmfield+*mightnotbelargeenoughtoholdtheoffsetofthestart+*addressofthecallee'sJITedimagefrom__bpf_call_base+*+*insuchcases,wecanlookupthestartaddressofacallee+*byusingitssubprogid,availablefromtheofffieldof+*thecallinstruction,asanindexforthislist+*/+func[i]->aux->func=func;+func[i]->aux->func_cnt=env->subprog_cnt;}for(i=0;i<env->subprog_cnt;i++){old_bpf_func=func[i]->bpf_func;
From: Sandipan Das <hidden> Date: 2018-05-24 06:57:09
For multi-function programs, loading the address of a callee
function to a register requires emitting instructions whose
count varies from one to five depending on the nature of the
address.
Since we come to know of the callee's address only before the
extra pass, the number of instructions required to load this
address may vary from what was previously generated. This can
make the JITed image grow or shrink.
To avoid this, we should generate a constant five-instruction
when loading function addresses by padding the optimized load
sequence with NOPs.
Signed-off-by: Sandipan Das <redacted>
---
arch/powerpc/net/bpf_jit_comp64.c | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
@@ -167,25 +167,37 @@ static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)staticvoidbpf_jit_emit_func_call(u32*image,structcodegen_context*ctx,u64func){+unsignedinti,ctx_idx=ctx->idx;++/* Load function address into r12 */+PPC_LI64(12,func);++/* For bpf-to-bpf function calls, the callee's address is unknown+*untilthelastextrapass.Asseenabove,weusePPC_LI64()to+*loadthecallee'saddress,butthismayoptimizethenumberof+*instructionsrequiredbasedonthenatureoftheaddress.+*+*Sincewedon'twantthenumberofinstructionsemittedtochange,+*wepadtheoptimizedPPC_LI64()callwithNOPstoguaranteethat+*wealwayshaveafive-instructionsequence,whichisthemaximum+*thatPPC_LI64()canemit.+*/+for(i=ctx->idx-ctx_idx;i<5;i++)+PPC_NOP();+#ifdef PPC64_ELF_ABI_v1-/* func points to the function descriptor */-PPC_LI64(b2p[TMP_REG_2],func);-/* Load actual entry point from function descriptor */-PPC_BPF_LL(b2p[TMP_REG_1],b2p[TMP_REG_2],0);-/* ... and move it to LR */-PPC_MTLR(b2p[TMP_REG_1]);/**LoadTOCfromfunctiondescriptoratoffset8.*Wecanclobberr2sincewegetcalledthrougha*functionpointer(socallerwillsave/restorer2)*andsincewedon'tuseaTOCourself.*/-PPC_BPF_LL(2,b2p[TMP_REG_2],8);-#else-/* We can clobber r12 */-PPC_FUNC_ADDR(12,func);-PPC_MTLR(12);+PPC_BPF_LL(2,12,8);+/* Load actual entry point from function descriptor */+PPC_BPF_LL(12,12,0);#endif++PPC_MTLR(12);PPC_BLRL();}
From: Sandipan Das <hidden> Date: 2018-05-24 06:57:12
This adds new two new fields to struct bpf_prog_info. For
multi-function programs, these fields can be used to pass
a list of kernel symbol addresses for all functions in a
given program to userspace using the bpf system call with
the BPF_OBJ_GET_INFO_BY_FD command.
When bpf_jit_kallsyms is enabled, we can get the address
of the corresponding kernel symbol for a callee function
and resolve the symbol's name. The address is determined
by adding the value of the call instruction's imm field
to __bpf_call_base. This offset gets assigned to the imm
field by the verifier.
For some architectures, such as powerpc64, the imm field
is not large enough to hold this offset.
We resolve this by:
[1] Assigning the subprog id to the imm field of a call
instruction in the verifier instead of the offset of
the callee's symbol's address from __bpf_call_base.
[2] Determining the address of a callee's corresponding
symbol by using the imm field as an index for the
list of kernel symbol addresses now available from
the program info.
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Sandipan Das <redacted>
---
v3:
- Copy addresses to jited_ksyms only if bpf_dump_raw_ok()
is true.
- Move new fields to the end of bpf_prog_info to avoid
breaking userspace.
---
include/uapi/linux/bpf.h | 2 ++
kernel/bpf/syscall.c | 25 +++++++++++++++++++++++++
kernel/bpf/verifier.c | 7 +------
3 files changed, 28 insertions(+), 6 deletions(-)
@@ -1933,6 +1933,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,if(!capable(CAP_SYS_ADMIN)){info.jited_prog_len=0;info.xlated_prog_len=0;+info.nr_jited_ksyms=0;gotodone;}
@@ -1981,6 +1982,30 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,}}+ulen=info.nr_jited_ksyms;+info.nr_jited_ksyms=prog->aux->func_cnt;+if(info.nr_jited_ksyms&&ulen){+if(bpf_dump_raw_ok()){+u64__user*user_ksyms;+ulongksym_addr;+u32i;++/* copy the address of the kernel symbol+*correspondingtoeachfunction+*/+ulen=min_t(u32,info.nr_jited_ksyms,ulen);+user_ksyms=u64_to_user_ptr(info.jited_ksyms);+for(i=0;i<ulen;i++){+ksym_addr=(ulong)prog->aux->func[i]->bpf_func;+ksym_addr&=PAGE_MASK;+if(put_user((u64)ksym_addr,&user_ksyms[i]))+return-EFAULT;+}+}else{+info.jited_ksyms=0;+}+}+done:if(copy_to_user(uinfo,&info,info_len)||put_user(info_len,&uattr->info.info_len))
From: Sandipan Das <hidden> Date: 2018-05-24 06:57:12
This adds support for bpf-to-bpf function calls in the powerpc64
JIT compiler. The JIT compiler converts the bpf call instructions
to native branch instructions. After a round of the usual passes,
the start addresses of the JITed images for the callee functions
are known. Finally, to fixup the branch target addresses, we need
to perform an extra pass.
Because of the address range in which JITed images are allocated
on powerpc64, the offsets of the start addresses of these images
from __bpf_call_base are as large as 64 bits. So, for a function
call, we cannot use the imm field of the instruction to determine
the callee's address. Instead, we use the alternative method of
getting it from the list of function addresses in the auxiliary
data of the caller by using the off field as an index.
Signed-off-by: Sandipan Das <redacted>
---
v3:
- Fix memory leak for jit_data when we fail to allocated addrs.
- Remove unnecessary bpf_jit_binary_lock_ro() call.
---
arch/powerpc/net/bpf_jit_comp64.c | 76 +++++++++++++++++++++++++++++++++------
1 file changed, 66 insertions(+), 10 deletions(-)
@@ -268,7 +268,7 @@ static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32/* Assemble the body code between the prologue & epilogue */staticintbpf_jit_build_body(structbpf_prog*fp,u32*image,structcodegen_context*ctx,-u32*addrs)+u32*addrs,boolextra_pass){conststructbpf_insn*insn=fp->insnsi;intflen=fp->len;
@@ -724,11 +724,25 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,break;/*-*Callkernelhelper+*Callkernelhelperorbpffunction*/caseBPF_JMP|BPF_CALL:ctx->seen|=SEEN_FUNC;-func=(u8*)__bpf_call_base+imm;++/* bpf function call */+if(insn[i].src_reg==BPF_PSEUDO_CALL)+if(!extra_pass)+func=NULL;+elseif(fp->aux->func&&off<fp->aux->func_cnt)+/* use the subprog id from the off+*fieldtolookupthecalleeaddress+*/+func=(u8*)fp->aux->func[off]->bpf_func;+else+return-EINVAL;+/* kernel helper call */+else+func=(u8*)__bpf_call_base+imm;bpf_jit_emit_func_call(image,ctx,(u64)func);
@@ -947,7 +993,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)/* Now build the prologue, body code & epilogue for real. */cgctx.idx=0;bpf_jit_build_prologue(code_base,&cgctx);-bpf_jit_build_body(fp,code_base,&cgctx,addrs);+bpf_jit_build_body(fp,code_base,&cgctx,addrs,extra_pass);bpf_jit_build_epilogue(code_base,&cgctx);if(bpf_jit_enable>1)
From: Sandipan Das <hidden> Date: 2018-05-24 06:57:16
Syncing the bpf.h uapi header with tools so that struct
bpf_prog_info has the two new fields for passing on the
addresses of the kernel symbols corresponding to each
function in a program.
Signed-off-by: Sandipan Das <redacted>
---
v3:
- Move new fields to the end of bpf_prog_info to avoid
breaking userspace.
---
tools/include/uapi/linux/bpf.h | 2 ++
1 file changed, 2 insertions(+)
From: Sandipan Das <hidden> Date: 2018-05-24 06:57:18
Currently, we resolve the callee's address for a JITed function
call by using the imm field of the call instruction as an offset
from __bpf_call_base. If bpf_jit_kallsyms is enabled, we further
use this address to get the callee's kernel symbol's name.
For some architectures, such as powerpc64, the imm field is not
large enough to hold this offset. So, instead of assigning this
offset to the imm field, the verifier now assigns the subprog
id. Also, a list of kernel symbol addresses for all the JITed
functions is provided in the program info. We now use the imm
field as an index for this list to lookup a callee's symbol's
address and resolve its name.
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Sandipan Das <redacted>
Reviewed-by: Jakub Kicinski <redacted>
---
v3:
- Avoid using redundant pointers.
- Fix indentation.
v2:
- Order variables from longest to shortest.
- Make sure that ksyms_ptr and ksyms_len are always initialized.
- Simplify code.
---
tools/bpf/bpftool/prog.c | 24 ++++++++++++++++++++++++
tools/bpf/bpftool/xlated_dumper.c | 10 +++++++++-
tools/bpf/bpftool/xlated_dumper.h | 2 ++
3 files changed, 35 insertions(+), 1 deletion(-)
@@ -174,7 +174,11 @@ static const char *print_call_pcrel(struct dump_data *dd,unsignedlongaddress,conststructbpf_insn*insn){-if(sym)+if(!dd->nr_jited_ksyms)+/* Do not show address for interpreted programs */+snprintf(dd->scratch_buff,sizeof(dd->scratch_buff),+"%+d",insn->off);+elseif(sym)snprintf(dd->scratch_buff,sizeof(dd->scratch_buff),"%+d#%s",insn->off,sym->name);else
From: Sandipan Das <hidden> Date: 2018-05-24 06:57:21
Currently, for multi-function programs, we cannot get the JITed
instructions using the bpf system call's BPF_OBJ_GET_INFO_BY_FD
command. Because of this, userspace tools such as bpftool fail
to identify a multi-function program as being JITed or not.
With the JIT enabled and the test program running, this can be
verified as follows:
# cat /proc/sys/net/core/bpf_jit_enable
1
Before applying this patch:
# bpftool prog list
1: kprobe name foo tag b811aab41a39ad3d gpl
loaded_at 2018-05-16T11:43:38+0530 uid 0
xlated 216B not jited memlock 65536B
...
# bpftool prog dump jited id 1
no instructions returned
After applying this patch:
# bpftool prog list
1: kprobe name foo tag b811aab41a39ad3d gpl
loaded_at 2018-05-16T12:13:01+0530 uid 0
xlated 216B jited 308B memlock 65536B
...
# bpftool prog dump jited id 1
0: nop
4: nop
8: mflr r0
c: std r0,16(r1)
10: stdu r1,-112(r1)
14: std r31,104(r1)
18: addi r31,r1,48
1c: li r3,10
...
Signed-off-by: Sandipan Das <redacted>
---
v4:
- If the image allocated in userspace is not large enough,
fill it up till the end even if the last JITed image can
only be copied partially.
---
kernel/bpf/syscall.c | 37 ++++++++++++++++++++++++++++++++++---
1 file changed, 34 insertions(+), 3 deletions(-)
@@ -1970,13 +1970,44 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,*foroffload.*/ulen=info.jited_prog_len;-info.jited_prog_len=prog->jited_len;+if(prog->aux->func_cnt){+u32i;++info.jited_prog_len=0;+for(i=0;i<prog->aux->func_cnt;i++)+info.jited_prog_len+=prog->aux->func[i]->jited_len;+}else{+info.jited_prog_len=prog->jited_len;+}+if(info.jited_prog_len&&ulen){if(bpf_dump_raw_ok()){uinsns=u64_to_user_ptr(info.jited_prog_insns);ulen=min_t(u32,info.jited_prog_len,ulen);-if(copy_to_user(uinsns,prog->bpf_func,ulen))-return-EFAULT;++/* for multi-function programs, copy the JITed+*instructionsforallthefunctions+*/+if(prog->aux->func_cnt){+u32len,free,i;+u8*img;++free=ulen;+for(i=0;i<prog->aux->func_cnt;i++){+len=prog->aux->func[i]->jited_len;+len=min_t(u32,len,free);+img=(u8*)prog->aux->func[i]->bpf_func;+if(copy_to_user(uinsns,img,len))+return-EFAULT;+uinsns+=len;+free-=len;+if(!free)+break;+}+}else{+if(copy_to_user(uinsns,prog->bpf_func,ulen))+return-EFAULT;+}}else{info.jited_prog_insns=0;}
From: Sandipan Das <hidden> Date: 2018-05-24 06:57:22
This adds new two new fields to struct bpf_prog_info. For
multi-function programs, these fields can be used to pass
a list of the JITed image lengths of each function for a
given program to userspace using the bpf system call with
the BPF_OBJ_GET_INFO_BY_FD command.
This can be used by userspace applications like bpftool
to split up the contiguous JITed dump, also obtained via
the system call, into more relatable chunks corresponding
to each function.
Signed-off-by: Sandipan Das <redacted>
---
include/uapi/linux/bpf.h | 2 ++
kernel/bpf/syscall.c | 20 ++++++++++++++++++++
2 files changed, 22 insertions(+)
@@ -2037,6 +2037,26 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,}}+ulen=info.nr_jited_func_lens;+info.nr_jited_func_lens=prog->aux->func_cnt;+if(info.nr_jited_func_lens&&ulen){+if(bpf_dump_raw_ok()){+u32__user*user_lens;+u32func_len,i;++/* copy the JITed image lengths for each function */+ulen=min_t(u32,info.nr_jited_func_lens,ulen);+user_lens=u64_to_user_ptr(info.jited_func_lens);+for(i=0;i<ulen;i++){+func_len=prog->aux->func[i]->jited_len;+if(put_user(func_len,&user_lens[i]))+return-EFAULT;+}+}else{+info.jited_func_lens=0;+}+}+done:if(copy_to_user(uinfo,&info,info_len)||put_user(info_len,&uattr->info.info_len))
From: Sandipan Das <hidden> Date: 2018-05-24 06:57:25
Syncing the bpf.h uapi header with tools so that struct
bpf_prog_info has the two new fields for passing on the
JITed image lengths of each function in a multi-function
program.
Signed-off-by: Sandipan Das <redacted>
---
tools/include/uapi/linux/bpf.h | 2 ++
1 file changed, 2 insertions(+)
From: Jakub Kicinski <hidden> Date: 2018-05-24 07:04:26
On Thu, 24 May 2018 12:26:54 +0530, Sandipan Das wrote:
This splits up the contiguous JITed dump obtained via the bpf
system call into more relatable chunks for each function in
the program. If the kernel symbols corresponding to these are
known, they are printed in the header for each JIT image dump
otherwise the masked start address is printed.
From: Daniel Borkmann <daniel@iogearbox.net> Date: 2018-05-24 07:31:23
On 05/24/2018 08:56 AM, Sandipan Das wrote:
[1] Support for bpf-to-bpf function calls in the powerpc64 JIT compiler.
[2] Provide a way for resolving function calls because of the way JITed
images are allocated in powerpc64.
[3] Fix to get JITed instruction dumps for multi-function programs from
the bpf system call.
[4] Fix for bpftool to show delimited multi-function JITed image dumps.
v4:
- Incorporate review comments from Jakub.
- Fix JSON output for bpftool.
v3:
- Change base tree tag to bpf-next.
- Incorporate review comments from Alexei, Daniel and Jakub.
- Make sure that the JITed image does not grow or shrink after
the last pass due to the way the instruction sequence used
to load a callee's address maybe optimized.
- Make additional changes to the bpf system call and bpftool to
make multi-function JITed dumps easier to correlate.
v2:
- Incorporate review comments from Jakub.
Sandipan Das (10):
bpf: support 64-bit offsets for bpf function calls
bpf: powerpc64: pad function address loads with NOPs
bpf: powerpc64: add JIT support for multi-function programs
bpf: get kernel symbol addresses via syscall
tools: bpf: sync bpf uapi header
tools: bpftool: resolve calls without using imm field
bpf: fix multi-function JITed dump obtained via syscall
bpf: get JITed image lengths of functions via syscall
tools: bpf: sync bpf uapi header
tools: bpftool: add delimiters to multi-function JITed dumps
arch/powerpc/net/bpf_jit_comp64.c | 110 ++++++++++++++++++++++++++++++--------
include/uapi/linux/bpf.h | 4 ++
kernel/bpf/syscall.c | 82 ++++++++++++++++++++++++++--
kernel/bpf/verifier.c | 22 +++++---
tools/bpf/bpftool/prog.c | 97 ++++++++++++++++++++++++++++++++-
tools/bpf/bpftool/xlated_dumper.c | 14 +++--
tools/bpf/bpftool/xlated_dumper.h | 3 ++
tools/include/uapi/linux/bpf.h | 4 ++
8 files changed, 301 insertions(+), 35 deletions(-)
From: Daniel Borkmann <daniel@iogearbox.net> Date: 2018-05-24 07:34:19
On 05/24/2018 08:56 AM, Sandipan Das wrote:
quoted hunk
For multi-function programs, loading the address of a callee
function to a register requires emitting instructions whose
count varies from one to five depending on the nature of the
address.
Since we come to know of the callee's address only before the
extra pass, the number of instructions required to load this
address may vary from what was previously generated. This can
make the JITed image grow or shrink.
To avoid this, we should generate a constant five-instruction
when loading function addresses by padding the optimized load
sequence with NOPs.
Signed-off-by: Sandipan Das <redacted>
---
arch/powerpc/net/bpf_jit_comp64.c | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
@@ -167,25 +167,37 @@ static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)staticvoidbpf_jit_emit_func_call(u32*image,structcodegen_context*ctx,u64func){+unsignedinti,ctx_idx=ctx->idx;++/* Load function address into r12 */+PPC_LI64(12,func);++/* For bpf-to-bpf function calls, the callee's address is unknown+*untilthelastextrapass.Asseenabove,weusePPC_LI64()to+*loadthecallee'saddress,butthismayoptimizethenumberof+*instructionsrequiredbasedonthenatureoftheaddress.+*+*Sincewedon'twantthenumberofinstructionsemittedtochange,+*wepadtheoptimizedPPC_LI64()callwithNOPstoguaranteethat+*wealwayshaveafive-instructionsequence,whichisthemaximum+*thatPPC_LI64()canemit.+*/+for(i=ctx->idx-ctx_idx;i<5;i++)+PPC_NOP();
By the way, I think you can still optimize this. The nops are not really
needed in case of insn->src_reg != BPF_PSEUDO_CALL since the address of
a normal BPF helper call will always be at a fixed location and known a
priori.
#ifdef PPC64_ELF_ABI_v1
- /* func points to the function descriptor */
- PPC_LI64(b2p[TMP_REG_2], func);
- /* Load actual entry point from function descriptor */
- PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_2], 0);
- /* ... and move it to LR */
- PPC_MTLR(b2p[TMP_REG_1]);
/*
* Load TOC from function descriptor at offset 8.
* We can clobber r2 since we get called through a
* function pointer (so caller will save/restore r2)
* and since we don't use a TOC ourself.
*/
- PPC_BPF_LL(2, b2p[TMP_REG_2], 8);
-#else
- /* We can clobber r12 */
- PPC_FUNC_ADDR(12, func);
- PPC_MTLR(12);
+ PPC_BPF_LL(2, 12, 8);
+ /* Load actual entry point from function descriptor */
+ PPC_BPF_LL(12, 12, 0);
#endif
+
+ PPC_MTLR(12);
PPC_BLRL();
}
From: Sandipan Das <hidden> Date: 2018-05-24 08:25:44
On 05/24/2018 01:04 PM, Daniel Borkmann wrote:
On 05/24/2018 08:56 AM, Sandipan Das wrote:
quoted
For multi-function programs, loading the address of a callee
function to a register requires emitting instructions whose
count varies from one to five depending on the nature of the
address.
Since we come to know of the callee's address only before the
extra pass, the number of instructions required to load this
address may vary from what was previously generated. This can
make the JITed image grow or shrink.
To avoid this, we should generate a constant five-instruction
when loading function addresses by padding the optimized load
sequence with NOPs.
Signed-off-by: Sandipan Das <redacted>
---
arch/powerpc/net/bpf_jit_comp64.c | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
@@ -167,25 +167,37 @@ static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)staticvoidbpf_jit_emit_func_call(u32*image,structcodegen_context*ctx,u64func){+unsignedinti,ctx_idx=ctx->idx;++/* Load function address into r12 */+PPC_LI64(12,func);++/* For bpf-to-bpf function calls, the callee's address is unknown+*untilthelastextrapass.Asseenabove,weusePPC_LI64()to+*loadthecallee'saddress,butthismayoptimizethenumberof+*instructionsrequiredbasedonthenatureoftheaddress.+*+*Sincewedon'twantthenumberofinstructionsemittedtochange,+*wepadtheoptimizedPPC_LI64()callwithNOPstoguaranteethat+*wealwayshaveafive-instructionsequence,whichisthemaximum+*thatPPC_LI64()canemit.+*/+for(i=ctx->idx-ctx_idx;i<5;i++)+PPC_NOP();
By the way, I think you can still optimize this. The nops are not really
needed in case of insn->src_reg != BPF_PSEUDO_CALL since the address of
a normal BPF helper call will always be at a fixed location and known a
priori.
Ah, true. Thanks for pointing this out. There are a few other things that
we are planning to do for the ppc64 JIT compiler. Will put out a patch for
this with that series.
- Sandipan
quoted
#ifdef PPC64_ELF_ABI_v1
- /* func points to the function descriptor */
- PPC_LI64(b2p[TMP_REG_2], func);
- /* Load actual entry point from function descriptor */
- PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_2], 0);
- /* ... and move it to LR */
- PPC_MTLR(b2p[TMP_REG_1]);
/*
* Load TOC from function descriptor at offset 8.
* We can clobber r2 since we get called through a
* function pointer (so caller will save/restore r2)
* and since we don't use a TOC ourself.
*/
- PPC_BPF_LL(2, b2p[TMP_REG_2], 8);
-#else
- /* We can clobber r12 */
- PPC_FUNC_ADDR(12, func);
- PPC_MTLR(12);
+ PPC_BPF_LL(2, 12, 8);
+ /* Load actual entry point from function descriptor */
+ PPC_BPF_LL(12, 12, 0);
#endif
+
+ PPC_MTLR(12);
PPC_BLRL();
}
From: Daniel Borkmann <daniel@iogearbox.net> Date: 2018-05-24 09:25:43
On 05/24/2018 10:25 AM, Sandipan Das wrote:
On 05/24/2018 01:04 PM, Daniel Borkmann wrote:
quoted
On 05/24/2018 08:56 AM, Sandipan Das wrote:
quoted
For multi-function programs, loading the address of a callee
function to a register requires emitting instructions whose
count varies from one to five depending on the nature of the
address.
Since we come to know of the callee's address only before the
extra pass, the number of instructions required to load this
address may vary from what was previously generated. This can
make the JITed image grow or shrink.
To avoid this, we should generate a constant five-instruction
when loading function addresses by padding the optimized load
sequence with NOPs.
Signed-off-by: Sandipan Das <redacted>
---
arch/powerpc/net/bpf_jit_comp64.c | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
@@ -167,25 +167,37 @@ static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)staticvoidbpf_jit_emit_func_call(u32*image,structcodegen_context*ctx,u64func){+unsignedinti,ctx_idx=ctx->idx;++/* Load function address into r12 */+PPC_LI64(12,func);++/* For bpf-to-bpf function calls, the callee's address is unknown+*untilthelastextrapass.Asseenabove,weusePPC_LI64()to+*loadthecallee'saddress,butthismayoptimizethenumberof+*instructionsrequiredbasedonthenatureoftheaddress.+*+*Sincewedon'twantthenumberofinstructionsemittedtochange,+*wepadtheoptimizedPPC_LI64()callwithNOPstoguaranteethat+*wealwayshaveafive-instructionsequence,whichisthemaximum+*thatPPC_LI64()canemit.+*/+for(i=ctx->idx-ctx_idx;i<5;i++)+PPC_NOP();
By the way, I think you can still optimize this. The nops are not really
needed in case of insn->src_reg != BPF_PSEUDO_CALL since the address of
a normal BPF helper call will always be at a fixed location and known a
priori.
Ah, true. Thanks for pointing this out. There are a few other things that
we are planning to do for the ppc64 JIT compiler. Will put out a patch for
this with that series.