Re: [PATCH bpf-next v2 3/6] bpf: x86: Support in-register struct arguments

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Aug 11, 2022 at 10:24 PM Yonghong Song <yhs@xxxxxx> wrote:
>
> In C, struct value can be passed as a function argument.
> For small structs, struct value may be passed in
> one or more registers. For trampoline based bpf programs,
> This would cause complication since one-to-one mapping between
> function argument and arch argument register is not valid
> any more.
>
> To support struct value argument and make bpf programs
> easy to write, the bpf program function parameter is
> changed from struct type to a pointer to struct type.
> The following is a simplified example.
>
> In one of later selftests, we have a bpf_testmod function:
>     struct bpf_testmod_struct_arg_2 {
>         long a;
>         long b;
>     };
>     noinline int
>     bpf_testmod_test_struct_arg_2(int a, struct bpf_testmod_struct_arg_2 b, int c) {
>         bpf_testmod_test_struct_arg_result = a + b.a + b.b + c;
>         return bpf_testmod_test_struct_arg_result;
>     }
>
> When a bpf program is attached to the bpf_testmod function
> bpf_testmod_test_struct_arg_2(), the bpf program may look like
>     SEC("fentry/bpf_testmod_test_struct_arg_2")
>     int BPF_PROG(test_struct_arg_3, int a, struct bpf_testmod_struct_arg_2 *b, int c)
>     {
>         t2_a = a;
>         t2_b_a = b->a;
>         t2_b_b = b->b;
>         t2_c = c;
>         return 0;
>     }
>
> Basically struct value becomes a pointer to the struct.
> The trampoline stack will be increased to store the stack values and
> the pointer to these values will be saved in the stack slot corresponding
> to that argument. For x86_64, the struct size is limited up to 16 bytes
> so the struct can fit in one or two registers. The struct size of more
> than 16 bytes is not supported now as our current use case is
> for sockptr_t in the argument. We could handle such large struct's
> in the future if we have concrete use cases.
>
> The main changes are in save_regs() and restore_regs(). The following
> illustrated the trampoline asm codes for save_regs() and restore_regs().
> save_regs():
>     /* first argument */
>     mov    DWORD PTR [rbp-0x18],edi
>     /* second argument: struct, save actual values and put the pointer to the slot */
>     lea    rax,[rbp-0x40]
>     mov    QWORD PTR [rbp-0x10],rax
>     mov    QWORD PTR [rbp-0x40],rsi
>     mov    QWORD PTR [rbp-0x38],rdx
>     /* third argument */
>     mov    DWORD PTR [rbp-0x8],esi
> restore_regs():
>     mov    edi,DWORD PTR [rbp-0x18]
>     mov    rsi,QWORD PTR [rbp-0x40]
>     mov    rdx,QWORD PTR [rbp-0x38]
>     mov    esi,DWORD PTR [rbp-0x8]

Not sure whether it was discussed before, but
why cannot we adjust the bpf side instead?
Technically struct passing between bpf progs was never
officially supported. llvm generates something.
Probably always passes by reference, but we can adjust
that behavior without breaking any programs because
we don't have bpf libraries. Programs are fully contained
in one or few files. libbpf can do static linking, but
without any actual libraries the chance of breaking
backward compat is close to zero.
Can we teach llvm to pass sizeof(struct) <= 16 in
two bpf registers?
Then we wouldn't need to have a discrepancy between
kernel function prototype and bpf fentry prog proto.
Both will have struct by value in the same spot.
The trampoline generation will be simpler for x86 and
its runtime faster too.
The other architectures that pass small structs by reference
can do a bit more work in the trampoline: copy up to 16 byte
and bpf prog side will see it as they were passed in 'registers'.
wdyt?



[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux