在x86上,gcc长期使用divdi3除法

时间:2021-11-20 16:49:15

When gcc sees multiplication or division of integer types that isn't supported in hardware, it generates call to special library function.

当gcc看到硬件中不支持的整数类型的乘法或除法时,它会生成对特殊库函数的调用。

http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines

http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html Integer-library-routines

According link above, long __divdi3 (long a, long b) used for division of long. However, here http://gcc.gnu.org/onlinedocs/gcc-3.3/gccint/Library-Calls.html divdi explained as "call for division of one signed double-word". When first source has cleary mapping of di suffix -> long arguments, second states divdi for double-word and udivdi for full-word (single, right?)

根据上面的链接,long __divdi3 (long a, long b)用于长分割。然而,这里的http://gcc.gnu.org/onlinedocs/gcc-3.3/gccint/Library-Calls.html divdi解释为“要求一个签名的双字的分割”。当第一个源有di后缀->长参数的清晰映射时,第二个状态divdi表示双字,udivdi表示全字(单字,对吧?)

When I compile simple example

当我编译简单的例子时。

int main(int argc, char *argv[]) {
    long long t1, t2, tr;

    t1 = 1;
    t2 = 1;
    tr = t1 / t2;

    return tr;
}

with gcc -Wall -O0 -m32 -march=i386 (gcc ver. 4.7.2) dissamble shows me

使用gcc -Wall -O0 -m32 -march=i386 (gcc ver)。4.7.2)dissamble显示我

    080483cc <main>:
     80483cc:       55                      push   %ebp
     80483cd:       89 e5                   mov    %esp,%ebp
     80483cf:       83 e4 f0                and    $0xfffffff0,%esp
     80483d2:       83 ec 30                sub    $0x30,%esp
     80483d5:       c7 44 24 28 01 00 00    movl   $0x1,0x28(%esp)
     80483dc:       00
     80483dd:       c7 44 24 2c 00 00 00    movl   $0x0,0x2c(%esp)
     80483e4:       00
     80483e5:       c7 44 24 20 01 00 00    movl   $0x1,0x20(%esp)
     80483ec:       00
     80483ed:       c7 44 24 24 00 00 00    movl   $0x0,0x24(%esp)
     80483f4:       00
     80483f5:       8b 44 24 20             mov    0x20(%esp),%eax
     80483f9:       8b 54 24 24             mov    0x24(%esp),%edx
     80483fd:       89 44 24 08             mov    %eax,0x8(%esp)
     8048401:       89 54 24 0c             mov    %edx,0xc(%esp)
     8048405:       8b 44 24 28             mov    0x28(%esp),%eax
     8048409:       8b 54 24 2c             mov    0x2c(%esp),%edx
     804840d:       89 04 24                mov    %eax,(%esp)
     8048410:       89 54 24 04             mov    %edx,0x4(%esp)
     8048414:       e8 17 00 00 00          call   8048430 <__divdi3>
     8048419:       89 44 24 18             mov    %eax,0x18(%esp)
     804841d:       89 54 24 1c             mov    %edx,0x1c(%esp)
     8048421:       8b 44 24 18             mov    0x18(%esp),%eax
     8048425:       c9                      leave
     8048426:       c3                      ret

Note 8048414: call 8048430 <__divdi3>.

注8048414:调用8048430 <__divdi3>。

I can't use gcc lib for my project and it's multiplatform. I hoped not to write all __* functions for all platforms (speed is not matter), but now I'm a bit confused.

我的项目不能使用gcc lib,它是多平台的。我希望不要为所有平台编写所有的__*函数(速度无关紧要),但是现在我有点困惑了。

Can somebody explain, why is there __divdi3 (not __divti3) call generated for long long int (64-bit) division?

有人能解释一下,为什么在长时间的int(64位)分区中会出现__divdi3(不是__divti3)的调用吗?

1 个解决方案

#1


2  

There is not word as word. On x86 machines, word usually means 16-bits. It's customary. Normally, a word is 16-bit or 32-bit number which´s width depends on activated mode (real or protected).

没有一个字是字。在x86机器上,word通常表示16位。这是惯例。通常情况下,一个单词是16位或32位的数值,´s宽度取决于激活模式(真实的或受保护的)。

I think that this terminology has been stated because linux/unix is generally running on many platforms. You can feel conflicts of term meanings on more tools. Live example is gdb, which uses w for 32-bit word and hw for 16-bit "half-word".

我认为这个术语已经说明,因为linux/unix通常在许多平台上运行。你可以在更多的工具上感受到术语意义的冲突。Live example是gdb,它使用w作为32位字,hw使用16位“半字”。

EDIT: There is another naming used for size of floats, but sometimes it's also used for integers. It is:

编辑:还有一个用于浮点数的命名,但有时也用于整数。它是:

  • s - single (precision, word?) for four byte integers (int) / floats (float)
  • s - 4字节整数(int) /浮点数(float)
  • d - double (precision) for eight byte integers (long or long long) / floats (double)
  • d - 8字节整数(长或长)/浮点数(双)
  • t - ten bytes for integers (long long) / floats (long double)
  • t - 10字节的整数(长)/浮点数(长双)

This naming is used for all arithmetic additions, like __divsi3, __divdi3, __divti3 or __mulsi3, __muldi3, __multi3... (and all u - unsigned - variants). That's the reason for __divdi3. Complete list is on this page.

这种命名用于所有算术加法,如__divsi3、__divdi3、__divti3或__mulsi3、__muldi3、__multi3…(以及所有u - unsigned -变异体)。这就是为什么要这样做。完整的列表在这一页上。

Division of 64-bit numbers on 32-bit machines uses advanced (and bit difficult) algorithm. You can use algorithm principe you've learned in school. Substracting small value from big number would waste time, but you can substract parts with different exponentiation separately and get the result faster. Here's simple pseudo-code for it (have a look on this answer about big-integers):

在32位机器上划分64位数字使用高级(和位困难)算法。你可以使用你在学校学到的算法原理。从大的数中除小的值将会浪费时间,但是你可以将不同指数的部分分别除去,从而更快地得到结果。这里有一个简单的伪代码(看看这个关于大整数的答案):

result = 0;
count = 0;
remainder = numerator;

while(highest_bit_of_divisor_not_set) {
    divisor = divisor << 1;
    count++;
}
while(remainder != 0) {
    if(remainder >= divisor) {
        remainder = remainder - divisor;
        result = result | (1 << count);
    }
    if(count == 0) {
        break;
    }
    divisor = divisor >> 1;
    count--;
}

#1


2  

There is not word as word. On x86 machines, word usually means 16-bits. It's customary. Normally, a word is 16-bit or 32-bit number which´s width depends on activated mode (real or protected).

没有一个字是字。在x86机器上,word通常表示16位。这是惯例。通常情况下,一个单词是16位或32位的数值,´s宽度取决于激活模式(真实的或受保护的)。

I think that this terminology has been stated because linux/unix is generally running on many platforms. You can feel conflicts of term meanings on more tools. Live example is gdb, which uses w for 32-bit word and hw for 16-bit "half-word".

我认为这个术语已经说明,因为linux/unix通常在许多平台上运行。你可以在更多的工具上感受到术语意义的冲突。Live example是gdb,它使用w作为32位字,hw使用16位“半字”。

EDIT: There is another naming used for size of floats, but sometimes it's also used for integers. It is:

编辑:还有一个用于浮点数的命名,但有时也用于整数。它是:

  • s - single (precision, word?) for four byte integers (int) / floats (float)
  • s - 4字节整数(int) /浮点数(float)
  • d - double (precision) for eight byte integers (long or long long) / floats (double)
  • d - 8字节整数(长或长)/浮点数(双)
  • t - ten bytes for integers (long long) / floats (long double)
  • t - 10字节的整数(长)/浮点数(长双)

This naming is used for all arithmetic additions, like __divsi3, __divdi3, __divti3 or __mulsi3, __muldi3, __multi3... (and all u - unsigned - variants). That's the reason for __divdi3. Complete list is on this page.

这种命名用于所有算术加法,如__divsi3、__divdi3、__divti3或__mulsi3、__muldi3、__multi3…(以及所有u - unsigned -变异体)。这就是为什么要这样做。完整的列表在这一页上。

Division of 64-bit numbers on 32-bit machines uses advanced (and bit difficult) algorithm. You can use algorithm principe you've learned in school. Substracting small value from big number would waste time, but you can substract parts with different exponentiation separately and get the result faster. Here's simple pseudo-code for it (have a look on this answer about big-integers):

在32位机器上划分64位数字使用高级(和位困难)算法。你可以使用你在学校学到的算法原理。从大的数中除小的值将会浪费时间,但是你可以将不同指数的部分分别除去,从而更快地得到结果。这里有一个简单的伪代码(看看这个关于大整数的答案):

result = 0;
count = 0;
remainder = numerator;

while(highest_bit_of_divisor_not_set) {
    divisor = divisor << 1;
    count++;
}
while(remainder != 0) {
    if(remainder >= divisor) {
        remainder = remainder - divisor;
        result = result | (1 << count);
    }
    if(count == 0) {
        break;
    }
    divisor = divisor >> 1;
    count--;
}