I’m working on an integrated SDK for powerpc microprocessor which has some kernel modules.
The kernel(3.12.37) and toolchain(powerpc gcc 4.9.2) provided by Yocto project.
When i make SDK in native machine(x86_64bit Ubuntu 14) by mentioned toolchain and kernel source, I see these warnings during compilation of kernel module:
WARNING: "__udivdi3" [modules/foo.ko] undefined! WARNING: "__umoddi3" [modules/foo.ko] undefined!
These warnings appear when i insmod
kernel module.
I realized that this functions are used for 64bit operations and libgcc has these functions.
this is compilation flags:
"-Wall -Werror -gdwarf-3 -Wframe-larger-than=16384 -mcpu=powerpc"
also, i gave this flag to compile statically "-Wl,-static-libgcc"
and didn’t work.
my questions are:
why does linker is going to use 64 bit functions which powerpc arch($KERNELDIR/arch/powerpc) doesn’t have? (Linker knows that ARCH is powerpc)
“in the kernel space, compiler does not use libgcc or other userspace functions and libs”, is this right? if not, please explain to me.
- and finally how can i solve this problem?
Thanks.
Advertisement
Answer
The compiler will generate code that calls functions in libgcc in order to perform certain operations. In this case, they are being called to perform the regular division (
/
) and modulo (%
) operations on 64-bit quantities.Correct, the kernel doesn’t use libgcc. Kernel code needs to be written to prevent the compiler making calls to functions in libgcc (in this case for division and module operations on 64-bit quantities).
Any code that does division or modulo operations on 64-bit quantities (apart from the native signed and unsigned
long
types on 64-bit architectures) needs to be rewritten to use special 64-bit division functions and macros provided by the Linux kernel instead of the regular/
and%
operators.In the old days, this was done by calling the
do_div(n,base)
macro defined by#include <asm/div64.h>
, but that has an unusual, non-functionlike interface in that it modifies the caller’sn
parameter in place to become the dividendn / base
in addition to returning the remaindern % base
.For new code, it is better to avoid the old
do_div(n,base)
macro and make use of the functions declared by#include <linux/math64.h>
. There are various functions defined there for signed and unsigned arguments and for both 32-bit and 64-bit remainders. You need to pick the most appropriate function to match the requirements of your code.