Linux内核上的64位除法

时间:2018-08-26 15:28:21

标签: c linux-kernel

我正在寻找64位划分算法,但不依赖于GPL许可证。

我在Hacker Delight书中找到了以下代码(图9-5):

unsigned long long udivdi3(unsigned long long u,
unsigned long long v) 
if (v >> 32 == 0) {
    if (u >> 32 < v)
        return DIVU(u, v) & 0xFFFFFFFF;
else {
.....
     }
}

问题在于“ return DIVU”计算得出的64/32除法数,因此不是我想要的。 该怎么办?

2 个答案:

答案 0 :(得分:1)

这是编译器-rt存在的原因。 __udivdi3最终调用中的Here is the C implementation,但请注意,还使用了特定于平台的程序集版本,例如在x86上。

但是,实际上,避免libgcc是没有意义的-它更成熟了,支持更多平台,并且由于运行时库异常,GPL在很大程度上已经放荡了-而且您绝对不应该为以下内容修改上游源这样,您无需提供任何修改的源代码。

答案 1 :(得分:0)

在Linux内核代码中执行64位分割似乎很棘手。我不确定您是否遇到了同样的问题,但这就是我所知道的。

看来指令集不能完全处理64位算术运算。看起来gcc发出了对辅助函数的调用。例如,在ARM上,如果我写

t /= 86400;

其中t是64位变量,我的内核构建失败,并带有“ undefined reference to '__aeabi_ldivmod'”。显然,内核没有链接到存在诸如__aeabi_ldivmod之类的函数的完整C库。

解决方案似乎是改为调用do_divdo_div实际上不是一个函数;它是在特定于体系结构的头文件中声明的宏。 (对于ARM,它在arch/arm/include/asm/div64.h中。x86有一个类似的文件。)

解决方案是将t /= 86400替换为

(void)do_div(t, 86400);

do_div将其第一个参数除以第二个参数,然后返回余数(在此示例中我将忽略)。

div64.h中有一条很大的评论,告诉您有关do_div以及如何使用它的更多信息。