如何在Linux内核中分割两个64位数字?

(C语法)的部分代码:

#define SINT64 long long int #define SINT32 long int SINT64 divRound(SINT64 dividend, SINT64 divisor) { SINT32 quotient1 = dividend / divisor; SINT32 modResult = dividend % divisor; SINT32 multResult = modResult * 2; SINT32 quotient2 = multResult / divisor; SINT64 result = quotient1 + quotient2; return ( result ); } 

现在,如果这是用户空间,我们可能甚至不会注意到我们的编译器正在为这些运算符生成代码(例如divdi3() )。 很有可能我们连“libgcc”都不知道。 问题是内核空间是不同的(例如没有libgcc)。 该怎么办?

抓取Google一段时间,注意几乎每个人都处理未签名的变体:

 #define UINT64 long long int #define UINT32 long int UINT64 divRound(UINT64 dividend, UINT64 divisor) { UINT32 quotient1 = dividend / divisor; UINT32 modResult = dividend % divisor; UINT32 multResult = modResult * 2; UINT32 quotient2 = multResult / divisor; UINT64 result = quotient1 + quotient2; return ( result ); } 

我知道如何解决这个问题:使用_do_div()_从asm / div64.h中覆盖udivdi3()umoddi3() 。 做对了吗? 错误。 签名与unsigned不同,sdivdi3()_不是简单地调用udivdi3() ,它们是单独的函数的一个原因。

你解决了这个问题吗? 你知道有一个图书馆能帮我做这个吗? 我真的被困住了,所以无论你在这里看到什么,我现在不正确的将是真正有帮助的。

谢谢,乍得

这是我真正天真的解决方案。 你的旅费可能会改变。

保持符号位,这是sign(dividend) ^ sign(divisor) 。 (或* ,或/ ,如果你将你的符号存储为1和-1,而不是假和真,基本上,如果任何一个为负,则为负,否则为正,否则为负。

然后,调用无符号除法函数的绝对值。 然后将签名重新贴上结果。

PS这实际上是如何在__divdi3中实现libgcc2.c (来自GCC 4.2.3,这是我的Ubuntu系统上安装的版本)。 我刚刚检查。 🙂

早在kernel v2.6.22中,这个功能就是在/linux/lib/div64.c中引入的。

我不认为(至少找不到方法) 克里斯的答案在这种情况下工作,因为do_div()实际上改变红利就地。 获取绝对值意味着一个临时变量,其值将改变我所需要的方式,但不能从我的__divdi3()覆盖中传出

除了模仿do_div()使用的技术外,在这一点上我没有看到__divdi3()逐个值的签名。

看起来好像我在这里向后弯,只是想出一个算法来实现我实际需要的64位/ 32位的分割。 这里增加的复杂性是,我有一堆使用'/'运算符的数字代码,并需要通过该代码,并用我的函数调用替换每个'/'。

尽管如此,我已经迫不及待了。

感谢乍得的任何后续行动

ldiv

编辑:重读标题,所以你可能要忽略这一点。 或者不是,取决于它是否有适当的非库版本。