littlekernel / lk

LK embedded kernel
MIT License
3.11k stars 611 forks source link

Adding the `-mgeneral-regs-only` flag breaks variadic functions #383

Open fdischner opened 11 months ago

fdischner commented 11 months ago

This issue was observed with the printf function, but seems to affect all variadic functions. The printf() function is in lib/libc/stdio.c, which is currently compiled with -mgeneral-regs-only on x86 and arm64 targets. The _printf_engine() function, however, is in lib/libc/printf.c, which does use floating point and is compiled without the -mgeneral-regs-only flag.

The issue is that, when compiling with -mgeneral-regs-only, the compiler assumes the variadic arguments cannot be float or double and so does not emit the necessary assembly to move arguments from floating point registers into the va_list that is passed to vfprintf(). However, if another source is compiled without this flag and calls printf(), then the compiler will pass float/double arguments in floating point registers, because it's unaware that printf() was compiled without this support. Thus, everything compiles and links without warnings or errors, but printing floating point values does not work.

Note that things get even worse when compiling with clang. Clang will happily compile floating point code with -mgeneral-regs-only without any warnings, but will convert it to a soft-float ABI. This seems to be a bug in clang (see https://reviews.llvm.org/D38479 and https://github.com/llvm/llvm-project/issues/30140), but there is no progress on a fix.

Would it maybe make sense to reverse the logic of when to apply -mgeneral-regs-only? So all sources would be compiled without the flag by default and then the flag would be applied only to those core kernel sources (and dependencies), which must not use floating point (and are known not to).