From: "Jose E. Marchesi" <jose.marchesi@oracle.com>
To: Eduard Zingerman <eddyz87@gmail.com>
Cc: Ihor Solodrai <ihor.solodrai@pm.me>,
"gcc@gcc.gnu.org" <gcc@gcc.gnu.org>,
Cupertino Miranda <cupertino.miranda@oracle.com>,
David Faust <david.faust@oracle.com>,
Elena Zannoni <elena.zannoni@oracle.com>,
Alexei Starovoitov <alexei.starovoitov@gmail.com>,
Manu Bretelle <chantra@meta.com>,
Mykola Lysenko <mykolal@meta.com>,
Yonghong Song <yonghong.song@linux.dev>,
bpf <bpf@vger.kernel.org>
Subject: Re: Errors compiling BPF programs from Linux selftests/bpf with GCC
Date: Fri, 03 Jan 2025 01:16:40 +0100 [thread overview]
Message-ID: <87v7uw21lj.fsf@oracle.com> (raw)
In-Reply-To: <64d8a1a7037c9bf1057799c04f2d5bb6bdad3bad.camel@gmail.com> (Eduard Zingerman's message of "Thu, 02 Jan 2025 15:04:30 -0800")
> On Thu, 2025-01-02 at 10:47 +0100, Jose E. Marchesi wrote:
>> Hi Ihor.
>> Thanks for working on this! :)
>>
>> > [...]
>> > Older versions compile the dummy program without errors, however on
>> > attempt to build the selftests there is a different issue: conflicting
>> > int64 definitions (full log at [6]).
>> >
>> > In file included from /usr/include/x86_64-linux-gnu/sys/types.h:155,
>> > from /usr/include/x86_64-linux-gnu/bits/socket.h:29,
>> > from /usr/include/x86_64-linux-gnu/sys/socket.h:33,
>> > from /usr/include/linux/if.h:28,
>> > from /usr/include/linux/icmp.h:23,
>> > from progs/test_cls_redirect_dynptr.c:10:
>> > /usr/include/x86_64-linux-gnu/bits/stdint-intn.h:27:19: error: conflicting types for ‘int64_t’; have ‘__int64_t’ {aka ‘long long int’}
>> > 27 | typedef __int64_t int64_t;
>> > | ^~~~~~~
>> > In file included from progs/test_cls_redirect_dynptr.c:6:
>> > /ci/workspace/bpfgcc.20240922/lib/gcc/bpf-unknown-none/15.0.0/include/stdint.h:43:24:
>> > note: previous declaration of ‘int64_t’ with type ‘int64_t’ {aka ‘long
>> > int’}
>> > 43 | typedef __INT64_TYPE__ int64_t;
>> > | ^~~~~~~
>>
>> I think this is what is going on:
>>
>> The BPF selftest is indirectly including glibc headers from the host
>> where it is being compiled. In this case your x86_64 ubuntu system.
>>
>> Many glibc headers include bits/wordsize.h, which in the case of x86_64
>> is:
>>
>> #if defined __x86_64__ && !defined __ILP32__
>> # define __WORDSIZE 64
>> #else
>> # define __WORDSIZE 32
>> #define __WORDSIZE32_SIZE_ULONG 0
>> #define __WORDSIZE32_PTRDIFF_LONG 0
>> #endif
>>
>> and then in bits/types.h:
>>
>> #if __WORDSIZE == 64
>> typedef signed long int __int64_t;
>> typedef unsigned long int __uint64_t;
>> #else
>> __extension__ typedef signed long long int __int64_t;
>> __extension__ typedef unsigned long long int __uint64_t;
>> #endif
>>
>> i.e. your BPF program ends using __WORDSIZE 32. This eventually leads
>> to int64_t being defined as `signed long long int' in stdint-intn.h, as
>> it would correspond to a x86_64 program running in 32-bit mode.
>>
>> GCC BPF, on the other hand, is a "baremetal" compiler and it provides a
>> small set of headers (including stdint.h) that implement standard C99
>> types like int64_t, adjusted to the BPF architecture.
>>
>> In this case there is a conflict between the 32-bit x86_64 definition of
>> int64_t and the one of BPF.
>>
>> PS: the other headers installed by GCC BPF are:
>> float.h iso646.h limits.h stdalign.h stdarg.h stdatomic.h stdbool.h
>> stdckdint.h stddef.h stdfix.h stdint.h stdnoreturn.h syslimits.h
>> tgmath.h unwind.h varargs.h
>
> I wondered how this works with clang, because it does not define
> __x86_64__ for bpf target. After staring and the output of -E:
> - for clang int64_t is defined once and definition originate from
> /usr/include/bits/stdint-intn.h included from /usr/include/stdint.h;
> - for gcc int64_t is defined two times, definitions originate from:
> - <gcc-install-path>/bpf-unknown-none/15.0.0/include/stdint.h
> - /usr/include/bits/stdint-intn.h included from /usr/include/sys/types.h.
>
> So, both refer to stdint-intn.h, but only gcc refers to
> compiler-specific stdint.h. This is so because of the structure of the
> clang's /usr/lib/clang/19/include/stdint.h:
>
> ...
> #if __STDC_HOSTED__ && __has_include_next(<stdint.h>)
> ...
> # include_next <stdint.h>
> ...
> #else
> ...
> typedef __INT64_TYPE__ int64_t;
> ...
> #endif
> ...
>
> The __STDC_HOSTED__ is defined as 1, thus when clang compiles the test case,
> compiler-specific stdint.h is included, but it's content is ifdef'ed out and
> it refers to system stdint.h instead. On the other hand, gcc-specific stdint.h
> unconditionally typedefs int64_t.
Yes, in the GCC BPF backend we are using
use_gcc_stdint=provide
which makes GCC to provide the version of stdint.h that assumes
freestanding ("baremetal") mode. If we changed it to use
use_gcc_stdint=wrap
then it would install a stdint.h that does somethins similar to what
clang does, at least in hosts providing C99 headers (note the lack of
__has_include_next):
#ifndef _GCC_WRAP_STDINT_H
#if __STDC_HOSTED__
# if defined __cplusplus && __cplusplus >= 201103L
# undef __STDC_LIMIT_MACROS
# define __STDC_LIMIT_MACROS
# undef __STDC_CONSTANT_MACROS
# define __STDC_CONSTANT_MACROS
# endif
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic" // include_next
# include_next <stdint.h>
#pragma GCC diagnostic pop
#else
# include "stdint-gcc.h"
#endif
#define _GCC_WRAP_STDINT_H
#endif
We could switch to "wrap" to align with clang, but in that case it would
be up to the user to provide a "host" stdint.h that contains sensible
definitions for BPF. The kernel selftests, for example, would need to
do so to avoid including /usr/include/stdint.h that more likely than not
will provide incorrect definitions for int64_t and friends...
>
> Links:
> - test case pre-processed by clang and gcc:
> https://gist.github.com/eddyz87/d381094d67979291bd8338655b15dd5e
> - LLVM source code for stdint.h:
> https://github.com/llvm/llvm-project/blob/c703b4645c79e889fd6a0f3f64f01f957d981aa4/clang/lib/Headers/stdint.h#L24
next prev parent reply other threads:[~2025-01-03 0:18 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-12-30 20:08 Errors compiling BPF programs from Linux selftests/bpf with GCC Ihor Solodrai
2024-12-30 20:24 ` Andrew Pinski
2024-12-30 20:36 ` Sam James
2024-12-30 20:59 ` Ihor Solodrai
2024-12-30 21:08 ` Sam James
2024-12-31 0:42 ` Alexei Starovoitov
2024-12-31 1:26 ` Ihor Solodrai
2024-12-31 4:09 ` Alexei Starovoitov
2025-01-02 9:47 ` Jose E. Marchesi
2025-01-02 17:35 ` Ihor Solodrai
2025-01-02 18:24 ` Jose E. Marchesi
2025-01-03 0:42 ` Eduard Zingerman
2025-01-03 13:23 ` Jose E. Marchesi
2025-01-02 23:04 ` Eduard Zingerman
2025-01-03 0:16 ` Jose E. Marchesi [this message]
2025-01-03 0:46 ` Eduard Zingerman
2025-01-03 10:17 ` Jose E. Marchesi
2025-01-03 12:52 ` Jose E. Marchesi
2025-01-03 23:48 ` Ihor Solodrai
2025-01-03 23:56 ` Andrew Pinski
2025-01-04 8:05 ` Jose E. Marchesi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87v7uw21lj.fsf@oracle.com \
--to=jose.marchesi@oracle.com \
--cc=alexei.starovoitov@gmail.com \
--cc=bpf@vger.kernel.org \
--cc=chantra@meta.com \
--cc=cupertino.miranda@oracle.com \
--cc=david.faust@oracle.com \
--cc=eddyz87@gmail.com \
--cc=elena.zannoni@oracle.com \
--cc=gcc@gcc.gnu.org \
--cc=ihor.solodrai@pm.me \
--cc=mykolal@meta.com \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.