Re: bpftool gen object doesn't handle GCC built BPF ELF files

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

 



On Mon, Aug 1, 2022 at 4:35 PM James Hilliard <james.hilliard1@xxxxxxxxx> wrote:
>
> On Mon, Aug 1, 2022 at 4:52 PM Andrii Nakryiko
> <andrii.nakryiko@xxxxxxxxx> wrote:
> >
> > On Sun, Jul 31, 2022 at 7:20 PM James Hilliard
> > <james.hilliard1@xxxxxxxxx> wrote:
> > >
> > > On Sun, Jul 10, 2022 at 2:22 PM Jose E. Marchesi
> > > <jose.marchesi@xxxxxxxxxx> wrote:
> > > >
> > > >
> > > > >>> On Sun, Jul 10, 2022 at 3:38 AM Jose E. Marchesi
> > > > >>> <jose.marchesi@xxxxxxxxxx> wrote:
> > > > >>>>
> > > > >>>>
> > > > >>>> > On Sat, Jul 9, 2022 at 4:41 PM Jose E. Marchesi
> > > > >>>> > <jose.marchesi@xxxxxxxxxx> wrote:
> > > > >>>> >>
> > > > >>>> >>
> > > > >>>> >> > On Sat, Jul 9, 2022 at 2:32 PM James Hilliard <james.hilliard1@xxxxxxxxx> wrote:
> > > > >>>> >> >>
> > > > >>>> >> >> On Sat, Jul 9, 2022 at 2:21 PM Jose E. Marchesi
> > > > >>>> >> >> <jose.marchesi@xxxxxxxxxx> wrote:
> > > > >>>> >> >> >
> > > > >>>> >> >> >
> >
> > Please trim your replies (and I don't know what your email client did,
> > but it completely ruined nested quote formatting)
>
> Yeah, not sure what happened there.
>
> >
> > [...]
> >
> > > > >>>>
> > > > >>>> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> > > > >>>> index e89cc9c885b3..887b78780099 100644
> > > > >>>> --- a/tools/lib/bpf/libbpf.c
> > > > >>>> +++ b/tools/lib/bpf/libbpf.c
> > > > >>>> @@ -1591,6 +1591,10 @@ static int bpf_object__init_global_data_maps(struct bpf_object *obj)
> > > > >>>>         for (sec_idx = 1; sec_idx < obj->efile.sec_cnt; sec_idx++) {
> > > > >>>>                 sec_desc = &obj->efile.secs[sec_idx];
> > > > >>>>
> > > > >>>> +                /* Skip recognized sections with size 0.  */
> > > > >>>> +                if (sec_desc->data && sec_desc->data->d_size == 0)
> > > > >>>> +                  continue;
> > > > >>>> +
> > > > >>>>                 switch (sec_desc->sec_type) {
> > > > >>>>                 case SEC_DATA:
> > > > >>>>                         sec_name = elf_sec_name(obj, elf_sec_by_idx(obj, sec_idx));
> > > > >>>
> > > > >>> Ok, skeleton is now getting generated successfully, however it differs from the
> > > > >>> clang version so there's a build error when we include/use the header:
> > > > >>> ../src/core/restrict-ifaces.c: In function ‘prepare_restrict_ifaces_bpf’:
> > > > >>> ../src/core/restrict-ifaces.c:45:14: error: ‘struct
> > > > >>> restrict_ifaces_bpf’ has no member named ‘rodata’; did you mean
> > > > >>> ‘data’?
> > > > >>>    45 |         obj->rodata->is_allow_list = is_allow_list;
> > > > >>>       |              ^~~~~~
> > > > >>>       |              data
> > > > >>>
> > > > >>> The issue appears to be that clang generates "rodata" members in
> > > > >>> restrict_ifaces_bpf while with gcc we get "data" members instead.
> > > > >>
> > > > >> This is because the BPF GCC port is putting the
> > > > >>
> > > > >>   const volatile unsigned char is_allow_list = 0;
> > > > >>
> > > > >> in a .data section instead of .rodata, due to the `volatile'.  The
> > > > >> x86_64 GCC seems to use .rodata.
> > > > >>
> > > > >> Looking at why the PBF port does this...
> > > > >
> > > > > So, turns out GCC puts zero-initialized `const volatile' variables in
> > > > > .data sections (and not .rodata) in all the targets I have tried, like
> > > > > x86_64 and aarch64.
> > > > >
> > > > > So this is a LLVM and GCC divergence :/
> > > >
> > > > See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25521.
> > > >
> > > > You may try, as a workaround:
> > > >
> > > > __attribute__((section(".rodata"))) const volatile unsigned char is_allow_list = 0;
> > > >
> > > > But that will use permissions "aw" for the .rodata section (and you will
> > > > get a warning from the assembler.)  It may be problematic for libbpf.
> > >
> > > So rather than try to force gcc to use the incorrect llvm .rodata
> > > section it looks
> > > like we can instead just force llvm to use the correct .data section like this:
> > > https://github.com/systemd/systemd/pull/24164
> > >
> >
> > There is a huge difference between variables in .rodata and .data.
> > .rodata variable's value is known to the BPF verifier at verification
> > time and this knowledge will be used to decide which code paths are
> > always or never taken (as one example). It's a crucial property and
> > important guarantee.
> >
> > If you don't care about that property, don't declare the variable as `const`.
> >
> > So no, it's not llvm putting `const` variable into .rodata
> > incorrectly, but GCC is trying to be smart and just because variable
> > is declared volatile is putting *const* variable into read-write .data
> > section. It's declared as const, and yes it's volatile to make sure
> > that compiler isn't too smart about optimizing away read operations.
>
> Isn't const volatile generating a .rodata section(like llvm is doing) a spec
> violation?
> https://github.com/llvm/llvm-project/issues/56468
>
> > But it's still a const read-only variable from the perspective of that
> > BPF C code.
> >
> > If you don't care about the read-only nature of that variable, drop
> > the const and make it into a non-read-only variable.
> >
> > And please stop proposing hacks to be added to perfectly valid systemd
> > BPF source code (I replied on [0] as well).
>
> From my understanding gcc is correctly putting a const volatile variable
> in .data while llvm is incorrectly putting it in .rodata, is the gcc behavior
> here invalid or is the llvm behavior invalid?

>From link you left to C standard, it does seem like that side-note
*implies* that const volatile should be put into .data, but it's a)
implied b) is quite arguable about assumptions that this data has to
be in modifiable section, and c) entire CO-RE feature detection and
guarding relies on having `const volatile` variables in .rodata and
mark them as read-only for BPF verifier to allow dead code
elimination. Changing c) would break entire CO-RE ecosystem.

Seems like this issue was raised by Ulrich Drepper back in 2005 ([0])
and he was also confused about GCC's behavior, btw.

So either way, at the very least for BPF target we can't change this
and I still think it's more logical to put const variables into
.rodata, regardless of side notes in C standard.


As for systemd's program and its is_allow_list ([1]), to unblock
yourself you can drop const because systemd doesn't rely on read-only
guarantees of that variable anyways. It's much more critical in
feature-detection use cases. But let's try to converge discussion in
one place (preferably here), it's quite inconvenient to either reply
the same thing twice here and on Github, or cross-reference lore and
Github.


  [0] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25521
  [1] https://github.com/systemd/systemd/pull/24164#issuecomment-1203207372

>
> >
> >   [0] https://github.com/systemd/systemd/pull/24164#issuecomment-1201806413
> >
> >
> > [...]




[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