18

在 32 位 Linux 内核上编译内核模块会导致

"__udivdi3" [mymodule.ko] undefined!
"__umoddi3" [mymodule.ko] undefined!

在 64 位系统上一切正常。据我所知,原因是 32 位 Linux 内核不支持 64 位整数除法和取模。

如何找到发出 64 位操作的代码。它们很难手动找到,因为我无法轻松检查“/”是 32 位宽还是 64 位宽。如果“正常”函数未定义,我可以对它们进行 grep,但这在这里是不可能的。还有另一种搜索参考文献的好方法吗?某种“机器代码grep”?

该模块由数千行代码组成。我真的不能手动检查每一行。

4

3 回答 3

24

首先,您可以使用do_div宏进行 64 位除法。(注意原型是uint32_t do_div(uint64_t dividend, uint32_t divisor)并且“ dividend”可以被多次评估。

{
    unsigned long long int x = 6;
    unsigned long int y = 4;
    unsigned long int rem;

    rem = do_div(x, y);
    /* x now contains the result of x/y */
}

此外,您应该能够在代码中找到long long int(或uint64_t)类型的用法,或者,您可以使用-g标志构建模块并objdump -S用于获取源注释的反汇编。

注意:这适用于 2.6 内核,我没有检查任何更低的使用情况

于 2009-06-30T14:00:18.773 回答
5

实际上,32位Linux 内核支持64 位整数除法和取模。但是,您必须使用正确的宏来执行此操作(哪些取决于您的内核版本,因为最近创建了新的更好的 IIRC)。宏将以最有效的方式为您编译的任何架构做正确的事情。

找到它们的使用位置的最简单方法是(如@shodanex 的回答中所述)生成汇编代码;IIRC,这样做的方法类似于make directory/module.s(连同您已经必须传递给的任何参数make)。下一个最简单的方法是反汇编.o文件(使用类似的东西objdump --disassemble)。两种方式都将为您提供生成调用的函数(并且,如果您知道如何阅读汇编,则大致了解函数中发生除法的位置)。

于 2009-06-30T13:53:04.200 回答
4

在编译阶段之后,您应该能够获得一些记录在案的程序集,并查看是否调用了这些函数。尝试弄乱 CFLAGS 并添加 -S 标志。编译应该在汇编阶段停止。然后,您可以在程序集文件中对有问题的函数调用进行 grep。

于 2009-06-30T13:42:31.493 回答