We use the compiler intrinsics without the C library header files for
everything else, so doing so for <stdarg.h> seems to actually be a
clarification and improvement.
This is an exaggeration. On several architectures, the kernel cannot
use the vector built-ins directly. Some of the implementing headers are
very special and intertwined with the compiler. <stdarg.h> is currently
not such a case, but it's just not technically not feasible to avoid
dependencies on all compiler headers. I think this considerably weakens
the case against <stdarg.h> because the compiler version is so obviously
harmless.
What the kernel is doing here is imposing an unnecesary constraint on
compiler development. Basically, you are telling compiler writers that
implementing features with the help of header files is a bad idea
because it makes it more difficult to use them from the kernel. (See
the proposed exceptions for vector code.)
Thanks,
Florian
On Mon, Sep 06, 2021 at 08:27:25PM +0200, Florian Weimer wrote:
* Linus Torvalds:
quoted
We use the compiler intrinsics without the C library header files for
everything else, so doing so for <stdarg.h> seems to actually be a
clarification and improvement.
This is an exaggeration. On several architectures, the kernel cannot
use the vector built-ins directly. Some of the implementing headers are
very special and intertwined with the compiler. <stdarg.h> is currently
not such a case, but it's just not technically not feasible to avoid
dependencies on all compiler headers. I think this considerably weakens
the case against <stdarg.h> because the compiler version is so obviously
harmless.
Exactly Florian. Thank you for so clearly making the point.
What the kernel is doing here is imposing an unnecesary constraint on
compiler development. Basically, you are telling compiler writers that
implementing features with the help of header files is a bad idea
because it makes it more difficult to use them from the kernel. (See
the proposed exceptions for vector code.)
Either it will constrain the compiler development, or perhaps more
likely, building the kernel will break in ways that the kernel people
will blame the compiler developers for.
The compiler headers (standard or arch-specific, same reason here) are
there because it decouples the user (that doesn't mean "userland", it
means the kernel here) from the builtins. Decoupling has many
advantages. The most obvious in general is you can use nicer names in
a header file, names that can step on the user's toes (like "bool" vs.
"_Bool", which is essentially all that <stdbool.h> does). But another
huge advantage of decoupling is it allows the compiler more freedom in
bugfixing (or any other maintenance / new development).
It is low probability that there are bugs in the compiler's standard
headers, and it's not likely the kernel's ad-hoc imitation of it has
bugs, this is all so small after all (but have I mentioned the
c46bbf5d2def commit?)
So there is no big pressure for changing anything here. But OTOH it
clearly is not a good idea to remove the existing uses of standard
headers. No upsides, various downsides, and some of those can be very
costly.
Segher
From: Jakub Jelinek <hidden> Date: 2021-09-06 20:14:48
On Mon, Sep 06, 2021 at 02:48:08PM -0500, Segher Boessenkool wrote:
quoted
This is an exaggeration. On several architectures, the kernel cannot
use the vector built-ins directly. Some of the implementing headers are
very special and intertwined with the compiler. <stdarg.h> is currently
not such a case, but it's just not technically not feasible to avoid
dependencies on all compiler headers. I think this considerably weakens
the case against <stdarg.h> because the compiler version is so obviously
harmless.
Exactly Florian. Thank you for so clearly making the point.
Yes. While stdarg.h builtins haven't changed for a while (we had some since
~ 1999, changed them incompatibly in 2000 and again in 2002 and not since then
and I'm not aware of plans to change them in the near future), e.g. for the
backend intrinsics, we change some every year or two, the only guaranteed APIs are
those provided by the headers (x86intrin.h/*mmintrin.h etc. on x86,
arm_{neon,sve}.h etc. on arm*, ...) and the underlying builtins are
sometimes removed, further ones added, etc.
stdarg.h is also such a header, although admittedly much simpler and less
likely to change.
I must say I don't understand the argument about uninstalled compilers,
uninstalled compilers work just fine if one supplies the right include path
for them, for C it is trivial and apparently the kernel has been already
doing that through -nostdinc -isystem .../include, for C++ a little bit
harder but we have a script for that.
Jakub
On Mon, Sep 6, 2021 at 1:14 PM Jakub Jelinek [off-list ref] wrote:
the only guaranteed APIs are
those provided by the headers (x86intrin.h/*mmintrin.h etc. on x86,
arm_{neon,sve}.h etc. on arm*, ...)
You guys realize we don't use those, do you?
And you don't seem to realize that you are actively arguing *AGAINST*
what you think you argue for.
That "immintrin.h" file, for example, is simply not usable for the
kernel. I just checked.
Why? Because it ends up doing exactly all those things that MUST NOT
be done for the kernel.
In file included from
/usr/lib/gcc/x86_64-redhat-linux/11/include/xmmintrin.h:34,
from
/usr/lib/gcc/x86_64-redhat-linux/11/include/immintrin.h:31,
from t.c:1:
/usr/lib/gcc/x86_64-redhat-linux/11/include/mm_malloc.h:27:10:
fatal error: stdlib.h: No such file or directory
27 | #include <stdlib.h>
| ^~~~~~~~~~
Oops.
And no, it doesn't work trying to include some specific avx2intrin.h
file either:
/usr/lib/gcc/x86_64-redhat-linux/11/include/avx2intrin.h:25:3:
error: #error "Never use <avx2intrin.h> directly; include
<immintrin.h> instead."
25 | # error "Never use <avx2intrin.h> directly; include
<immintrin.h> instead."
| ^~~~~
Very similar things happens if you try to use that <stdint.h> file
that somebody mentioned earlier.
Guys, you don't understand how limited the kernel header files are - on purpose.
You also don't seem to realize how hard it is to separate out the
user-land crap that we really cannot use, and must not use.
And you think that we're making it harder for compiler people, but
that's not at all the case.
You really don't want to deal with us saying "you can't do that" when
you do something that is
Yes, <stdarg.h> has historically worked for us, and it's pretty much
the only one.
All your arguments about how people need to use the standard headers
are basically worthless, because you have never actually tried to use
them in a standalone project, have you?
So just face it - stdarg.h is special.
And it's not clear that there's any reason why the kernel should
include the one that comes with the compiler, when the kernel cannot
use any of the other header files that come with the compiler anyway.
And ALL of your arguments about how we must use compiler header files
are COMPLETE GARBAGE, because you didn't even look at them, did you?
See?
So stop making arguments out of ignorance. Because that's literally
what you are doing. You've never tried to make those header files
standalone, and you don't have any idea of how nasty it would be if
you were forced to.
Linus
On Mon, Sep 6, 2021 at 2:08 PM Linus Torvalds
[off-list ref] wrote:
And you think that we're making it harder for compiler people, but
that's not at all the case.
You really don't want to deal with us saying "you can't do that" when
you do something that is
That got cut short when I went off to adding the examples of errors
that happen for those intrinsics headers.
But it was supposed to be "when you do something that is not valid in
the kernel".
There are some *very* core header files that the kernel cannot include
from outside. That "stdlib.h" thing already came up in the errors I
quoted.
But I think you'll find that you guys want to include things like
<errno.h> too, and you'll probably add others (<types.h>? things like
that) simply because they always work fine in user space, and you'd
not even notice.
Header file include chains get messy very quickly, and very easily.
I'm pretty sure you guys don't really want to deal with the pain that
is crazy kernel people that have their very bare environment.
So you may *think* you want the kernel to use your header files
"because compiler portability". Instead, you should be very thankful
that we don't, and that you don't have to deal with our mess any more
than you already do.
Linus
From: Jakub Jelinek <hidden> Date: 2021-09-06 21:52:36
On Mon, Sep 06, 2021 at 02:08:58PM -0700, Linus Torvalds wrote:
quoted
the only guaranteed APIs are
those provided by the headers (x86intrin.h/*mmintrin.h etc. on x86,
arm_{neon,sve}.h etc. on arm*, ...)
You guys realize we don't use those, do you?
The x86intrin.h/*mmintrin.h on x86 indeed not, arm_neon.h is used in the
kernel:
arch/arm64/include/asm/neon-intrinsics.h:#include <arm_neon.h>
arch/arm64/lib/xor-neon.c:#include <asm/neon-intrinsics.h>
The arm intrinsics headers are similar to the x86 ones in that the only
supported APIs are the ones provided by the headers, the underlying builtins
can change.
That "immintrin.h" file, for example, is simply not usable for the
kernel. I just checked.
Why? Because it ends up doing exactly all those things that MUST NOT
be done for the kernel.
In file included from
/usr/lib/gcc/x86_64-redhat-linux/11/include/xmmintrin.h:34,
from
/usr/lib/gcc/x86_64-redhat-linux/11/include/immintrin.h:31,
from t.c:1:
/usr/lib/gcc/x86_64-redhat-linux/11/include/mm_malloc.h:27:10:
fatal error: stdlib.h: No such file or directory
27 | #include <stdlib.h>
| ^~~~~~~~~~
Oops.
It is actually not that bad, stdlib.h is indeed included there because of 2
intrinsics out of more than 5000 and when one doesn't need those, just
#define _MM_MALLOC_H_INCLUDED
#include <x86intrin.h>
will get rid of the stdlib.h include and those 2 APIs that wouldn't be
usable in the kernel anyway. There is a stddef.h include too and that's it
(I must say I don't see the reason for that include though).
Other compiler provided headers (not talking about C++ now) also have no
or very limited includes, including stddef.h, stdarg.h, stdatomic.h, etc.
The only exceptions are tgmath.h which isn't usable without libc
math.h/complex.h, in some cases stdint.h and limits.h which are in some
configurations provided both by the C library and the compiler and include
each other in that case (but e.g. stdint.h has an alternate version that
only uses compiler provided builtin macros) and openacc.h.
Sure, the glibc headers are a different thing.
Jakub
On Mon, Sep 6, 2021 at 2:52 PM Jakub Jelinek [off-list ref] wrote:
It is actually not that bad, stdlib.h is indeed included there because of 2
intrinsics out of more than 5000 and when one doesn't need those, just
#define _MM_MALLOC_H_INCLUDED
.. and on clang?
In other words, your suggestion is unworkable, and actively works
against the whole point of "use standard headers". It's a joke. And
not in a good way.
There, I think you have to undefine __STDC_HOSTED__. Maybe by using
-ffreestanding?
Except if you use -ffreestanding, you lose some very bvasic
functionality (*), so we don't do that except for very special code
(our 16-bit realmode code does it, for example, and some very
low-level library implementations).
Just face the facts. Those header files weren't designed for the
kernel, and we've done all the special x86 FPU stuff using inline
asms.
Which is fine. But it all just proves your arguments about "you guys
have to use our header files" to be just a pipe dream, and not true.
The compiler header files may in some very limited situations be
usable. But in the general case? No.
And they should very much *not*at*all* be considered some kind of
sacred "this is the only way to do things". Because that is clearly
not true, and has *never* been true.
The usable header files are the odd special case, not the general case.
Really.
Is it really so hard to just admit that the kernel shouldn't use those
headers? When we have 30 years of experience in doing exactly that?
Linus
(*) iirc, with -ffreestanding gcc doesn't do all the basic memcpy()
optimizations. But I forget the exact details.
On Mon, Sep 06, 2021 at 02:08:58PM -0700, Linus Torvalds wrote:
On Mon, Sep 6, 2021 at 1:14 PM Jakub Jelinek [off-list ref] wrote:
quoted
the only guaranteed APIs are
those provided by the headers (x86intrin.h/*mmintrin.h etc. on x86,
arm_{neon,sve}.h etc. on arm*, ...)
You guys realize we don't use those, do you?
Linux does use the Arm and Power vector intrinsics (arm_neon.h and
altivec.h).
And you don't seem to realize that you are actively arguing *AGAINST*
what you think you argue for.
I have no idea what you think we are arguing for, only what we are.
That "immintrin.h" file, for example, is simply not usable for the
kernel. I just checked.
Yes. It cannot be used in freestanding environments; it includes a
header file we don't ship (<mm_malloc.h>, via <xmmintrin.h>). Or
perhaps we do ship it, but only on native systems? Same issue, anyway.
The top comment in the latter says
/* Implemented from the specification included in the Intel C++ Compiler
User Guide and Reference, version 9.0. */
so the shortcoming exists there already probably?
27 | #include <stdlib.h>
| ^~~~~~~~~~
Oops.
Yup, that is not a (freestanding) standard C header.
Very similar things happens if you try to use that <stdint.h> file
that somebody mentioned earlier.
Not at all. <stdint.h> *is* a standard C header, and we ship it, it
always works. If you find problems with it, please report them!
You also don't seem to realize how hard it is to separate out the
user-land crap that we really cannot use, and must not use.
We have worked very hard for many years to make this better. For the
freestanding headers only <limits.h> is still problematic, and you do
not need that one anyway, it is legacy more than anything else.
Segher
On Mon, Sep 06, 2021 at 02:24:39PM -0700, Linus Torvalds wrote:
There are some *very* core header files that the kernel cannot include
from outside. That "stdlib.h" thing already came up in the errors I
quoted.
But I think you'll find that you guys want to include things like
<errno.h> too, and you'll probably add others (<types.h>? things like
that) simply because they always work fine in user space, and you'd
not even notice.
Guess what. We actually test this. We do notice. Except we don't,
because all those problems do not actually exist.
Long ago there were issues. We do not live long ago now.
I'm pretty sure you guys don't really want to deal with the pain that
is crazy kernel people that have their very bare environment.
There are many other users that use freestanding environments. Most of
them do use the standard headers.
So you may *think* you want the kernel to use your header files
"because compiler portability". Instead, you should be very thankful
that we don't, and that you don't have to deal with our mess any more
than you already do.
We would like it to be *less* pain, *less* unnecessary work, that is why
we would like the kernel to use the compiler headers. Instead of what
the current patches do: getting rid of more of them, which will end up
as more work for everyone.
Segher
On Mon, Sep 06, 2021 at 11:52:18PM +0200, Jakub Jelinek wrote:
On Mon, Sep 06, 2021 at 02:08:58PM -0700, Linus Torvalds wrote:
There is a stddef.h include too and that's it
(I must say I don't see the reason for that include though).
Yeah me neither. Maybe the header used NULL before?
Other compiler provided headers (not talking about C++ now) also have no
or very limited includes, including stddef.h, stdarg.h, stdatomic.h, etc.
The only exceptions are tgmath.h which isn't usable without libc
math.h/complex.h,
<tgmath.h> is only for hosted environments. That requires a C library
for GCC (we do not implement this stuff ourselves). The compiler and
the C library have to work together to get this done, and the relation
between GCC and Glibc has been a bit too tight for this, it is true.
But a kernel build is not in a hosted environment.
in some cases stdint.h and limits.h which are in some
configurations provided both by the C library and the compiler and include
each other in that case (but e.g. stdint.h has an alternate version that
only uses compiler provided builtin macros) and openacc.h.
On what targets is <stdint.h> still problematic? And <limits.h>?
Segher
On Mon, Sep 06, 2021 at 03:24:41PM -0700, Linus Torvalds wrote:
On Mon, Sep 6, 2021 at 2:52 PM Jakub Jelinek [off-list ref] wrote:
quoted
It is actually not that bad, stdlib.h is indeed included there because of 2
intrinsics out of more than 5000 and when one doesn't need those, just
#define _MM_MALLOC_H_INCLUDED
.. and on clang?
Clang apparently has __MM_MALLOC_H as header guard here. But Clang
does say
#if __STDC_HOSTED__
#include <mm_malloc.h>
#endif
so they do not have this bug in the first place. GCC should fix this as
well. I filed <https://gcc.gnu.org/PR102231>. Thanks for bringing thisd
to our attention!
There, I think you have to undefine __STDC_HOSTED__. Maybe by using
-ffreestanding?
That defines it to 0, instead, as required by the C standard:
$ :|gcc -E -dM -|grep HOSTED
#define __STDC_HOSTED__ 1
$ :|gcc -E -dM - -ffreestanding|grep HOSTED
#define __STDC_HOSTED__ 0
Yes, that is how this works: the command line flag says how the macro
should be defined by the compiler (and changing it in your code is UB
btw).
Except if you use -ffreestanding, you lose some very bvasic
functionality (*),
(see below)
And they should very much *not*at*all* be considered some kind of
sacred "this is the only way to do things". Because that is clearly
not true, and has *never* been true.
Take for example <stdint.h>. There is no other way to find out what
types to use for exact-width integers. Unless you really want to do
typedef unsigned int __attribute__((mode (DI))) u64;
but that is rather unportable to other compilers but GCC.
<stdint.h> *is* the only portable way for getting exact-width integers
(and some other things). This is not something we decide, it is not
something you can decide, it follows directly from the C standard.
Using it is easy. Not using it leads to the forest of include files and
preprocessor conditionals the kernel currently uses.
The usable header files are the odd special case, not the general case.
Really.
Is it really so hard to just admit that the kernel shouldn't use those
headers? When we have 30 years of experience in doing exactly that?
That isn't the core issue at hand. Yes, Linux has implemented all of it
manually historically, and there even were good reasons for some of
that. That does not mean that it would be a good idea to throw out the
few standard C headers it does use, and implement those with compiler
internal interfaces instead, which we advice you against.
(*) iirc, with -ffreestanding gcc doesn't do all the basic memcpy()
optimizations. But I forget the exact details.
I would love to hear any details about that.
I do know the Glibc headers do (or did?) some premature optimisation
wrt. some mem* and str*, hurting performance on newer compilers. But
you should not be using the Glibc headers for compiling the kernel at
all anyway, so maybe there was some bug thereabouts?
Segher
On Tue, Sep 7, 2021 at 11:54 PM Segher Boessenkool
[off-list ref] wrote:
On Mon, Sep 06, 2021 at 11:52:18PM +0200, Jakub Jelinek wrote:
quoted
On Mon, Sep 06, 2021 at 02:08:58PM -0700, Linus Torvalds wrote:
There is a stddef.h include too and that's it
(I must say I don't see the reason for that include though).
Yeah me neither. Maybe the header used NULL before?
quoted
Other compiler provided headers (not talking about C++ now) also have no
or very limited includes, including stddef.h, stdarg.h, stdatomic.h, etc.
The only exceptions are tgmath.h which isn't usable without libc
math.h/complex.h,
<tgmath.h> is only for hosted environments. That requires a C library
for GCC (we do not implement this stuff ourselves). The compiler and
the C library have to work together to get this done, and the relation
between GCC and Glibc has been a bit too tight for this, it is true.
But a kernel build is not in a hosted environment.
quoted
in some cases stdint.h and limits.h which are in some
configurations provided both by the C library and the compiler and include
each other in that case (but e.g. stdint.h has an alternate version that
only uses compiler provided builtin macros) and openacc.h.
On what targets is <stdint.h> still problematic? And <limits.h>?
Since commit 0c79a8e29b5fcbcbfd611daf9d500cfad8370fcf
all architectures in the kernel space use the same fixed-width
types, which are defined by
include/uapi/asm-generic/int-ll64.h
So, u32 is always 'unsigned int',
and u64 is always 'unsigned long long'.
It is convenient for printk() in common code
because we can always use the 'll' prefix for u64.
u32 foo = 1;
u64 bar = 1;
printk("foo = %u\n", foo);
printk("bar = %llu\n, bar);
If we use compiler-provided <stdint.h>,
it is not convenient for printk() because
uint64_t is 'unsigned long' on some compilers
and 'unsigned long long' on others.
<intypes.h> provides macros such as PRIx64
uint32_t foo = 1;
uint64_t bar = 1;
printk("foo = %" PRIu32 "\n", foo);
printk("bar = %" PRIu64 "\n", bar);
This works, but ends up with ugly code,
which I want to avoid.
--
Best Regards
Masahiro Yamada