Re: libbpf/bpftool inconsistent handling og .data and .bss ?

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

 



TL;DR; there seems to be a compiler bug with clang-10 and -O2
when struct are in .data -- details below.

On Wed, Oct 7, 2020 at 8:35 PM Andrii Nakryiko
<andrii.nakryiko@xxxxxxxxx> wrote:
>
> On Wed, Oct 7, 2020 at 9:03 AM Luigi Rizzo <rizzo@xxxxxxxxxxxx> wrote:
> >
> > I am experiencing some weirdness in global variables handling
> > in bpftool and libbpf, as described below.
...
> > 2. .bss overrides from userspace are not seen in bpf at runtime
> >
> >     In foo_bpf.c I have "int x = 0;"
> >     In the userspace program, before foo_bpf__load(), I do
> >        obj->bss->x = 1
> >     but after attach, the bpf code does not see the change, ie
> >         "if (x == 0) { .. } else { .. }"
> >     always takes the first branch.
> >
> >     If I initialize "int x = 2" and then do
> >        obj->data->x = 1
> >     the update is seen correctly ie
> >           "if (x == 2) { .. } else { .. }"
> >      takes one or the other depending on whether userspace overrides
> >      the value before foo_bpf__load()
>
> This is quite surprising, given we have explicit selftests validating
> that all this works. And it seems to work. Please check
> prog_tests/skeleton.c and progs/test_skeleton.c. Can you try running
> it and confirm that it works in your setup?

Ah, this was non intuitive but obvious in hindsight:

.bss is zeroed by the kernel after load(), and since my program
changed the value before foo_bpf__load() , the memory was overwritten
with 0s. I could confirm this by printing the value after load.

If I update obj->data-><something> after __load(),
or even after __attach() given that userspace mmaps .bss and .data,
everything works as expected both for scalars and structs.

> >
> > 3. .data overrides do not seem to work for non-scalar types
> >     In foo_bpf.c I have
> >           struct one { int a; }; // type also visible to userspace
> >           struct one x { .a = 2 }; // avoid bugs #1 and #2
> >     If in userspace I do
> >           obj->data->x.a = 1
> >     the update is not seen in the kernel, ie
> >             "if (x.a == 2) { .. } else { .. }"
> >      always takes the first branch
> >
>
> Similarly, the same skeleton selftest tests this situation. So please
> check selftests first and report if selftests for some reason don't
> work in your case.

Actually test_skeleton.c does _not_ test for struct in .data,
only in .rodata and .bss

There seems to be a compiler error, at least with clang-10 and -O2

Note how the struct case the compiler uses '2' as immediate value
when reading, whereas in the scalar case it correctly dereferences
the pointer to the variable


Disassembly of section fexit/bar:

0000000000000000 foo_struct:
; int BPF_PROG(foo_struct) {
       0:       b7 01 00 00 02 00 00 00 r1 = 2
;   if (x.a == 2 || x.a > 10) { x.a += 10; }
       1:       15 01 02 00 02 00 00 00 if r1 == 2 goto +2 <LBB1_2>
       2:       b7 02 00 00 0b 00 00 00 r2 = 11
       3:       2d 12 04 00 00 00 00 00 if r2 > r1 goto +4 <LBB1_3>

0000000000000020 LBB1_2:
       4:       07 01 00 00 0a 00 00 00 r1 += 10
       5:       18 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r2 = 0 ll
       7:       63 12 00 00 00 00 00 00 *(u32 *)(r2 + 0) = r1

0000000000000040 LBB1_3:
; int BPF_PROG(foo_struct) {
       8:       b7 00 00 00 00 00 00 00 r0 = 0
       9:       95 00 00 00 00 00 00 00 exit

Disassembly of section fexit/baz:

0000000000000000 foo_scalar:
;   if (count_off == 2 || count_off > 10) { count_off += 10; }
       0:       18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
       2:       61 12 00 00 00 00 00 00 r2 = *(u32 *)(r1 + 0)
       3:       15 02 02 00 02 00 00 00 if r2 == 2 goto +2 <LBB2_2>
       4:       b7 03 00 00 0b 00 00 00 r3 = 11
       5:       2d 23 02 00 00 00 00 00 if r3 > r2 goto +2 <LBB2_3>

0000000000000030 LBB2_2:
       6:       07 02 00 00 0a 00 00 00 r2 += 10
       7:       63 21 00 00 00 00 00 00 *(u32 *)(r1 + 0) = r2

0000000000000040 LBB2_3:
; int BPF_PROG(foo_scalar) {
       8:       b7 00 00 00 00 00 00 00 r0 = 0
       9:       95 00 00 00 00 00 00 00 exit

------------

If I put the struct in .bss then it gets translated correctly:

Disassembly of section fexit/bar:

0000000000000000 foo_struct:
;   if (x.a == 2 || x.a > 10) { x.a += 10; }
       0:       18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
       2:       61 12 00 00 00 00 00 00 r2 = *(u32 *)(r1 + 0)
       3:       15 02 02 00 02 00 00 00 if r2 == 2 goto +2 <LBB1_2>
       4:       b7 03 00 00 0b 00 00 00 r3 = 11
       5:       2d 23 02 00 00 00 00 00 if r3 > r2 goto +2 <LBB1_3>

0000000000000030 LBB1_2:
       6:       07 02 00 00 0a 00 00 00 r2 += 10
       7:       63 21 00 00 00 00 00 00 *(u32 *)(r1 + 0) = r2

0000000000000040 LBB1_3:
; int BPF_PROG(foo_struct) {
       8:       b7 00 00 00 00 00 00 00 r0 = 0
       9:       95 00 00 00 00 00 00 00 exit



[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