为什么Linux内核使用do_div而不是/?

时间:2017-07-14 09:19:51

标签: c linux-kernel

对于64位除法,使用/do_div有什么区别? 只是为了提高性能?它是建筑依赖的吗?

The source code is here.

2 个答案:

答案 0 :(得分:4)

此模块中此宏和函数的用途是优化。内核代码中的注释非常清楚:

/*
 * do_div() is NOT a C function. It wants to return
 * two values (the quotient and the remainder), but
 * since that doesn't work very well in C, what it
 * does is:
 *
 * - modifies the 64-bit dividend _in_place_
 * - returns the 32-bit remainder
 *
 * This ends up being the most efficient "calling
 * convention" on x86.
 */

在内核中使用宏来计算单个步骤中的商和余数,而不是标准C中的2个操作,可能产生2个分区操作码。

事实上,Intel x86 CPU使用单条指令计算整数除法的商和余数。宏使用内联汇编来利用这一点,而C编译器可能不会将/%的2个单独计算优化为单个操作码。

在编写此代码时,大多数编译器都没有,并且除法操作码非常昂贵,因此Linus决定使用特殊函数来优化此计算。

请注意,C标准为此提供了一组函数(在<stdlib.h>中声明):

div_t div(int numer, int denom);
ldiv_t ldiv(long int numer, long int denom);
lldiv_t lldiv(long long int numer, long long int denom);

Linux内核的目标系统可能没有标准兼容的编译器,并且肯定早于其中一些标准添加,所以它有自己的这些函数版本作为宏,其他一些在同一模块中。

答案 1 :(得分:0)

需要该宏,因为在32位目标平台上,写入“ /”将无法链接。

内核中的C库不是您在用户空间中使用的C库。在用户空间C程序中,如果您的CPU没有64位除法指令,则C库将为您实现64位除法。

即使在32位平台上,也可以使用64位乘法,但是64位除法是不行的,并且会拒绝驱动程序,因为它不会通过编译。