-1

如何在 32 位机器上添加几个 32 位数字但不损失精度,即在 64 位“伪寄存器”eax:edx中。使用 Intel 语法汇编器。

4

3 回答 3

4

假设您要添加的 32 位数字在 EAX 和 EBX 中,并且是无符号的:

    xor edx,edx       ;Set edx to zero
    add eax,ebx
    adc edx,0         ;edx:eax = eax + ebx

这与在加法之前将值零扩展为 64 位,然后进行 64 位加法基本相同。

对于有符号整数,这将不起作用(例如“0 + (-1) != 0x00000000 + 0xFFFFFFFF != 0x00000000FFFFFFFF”),因为您需要符号扩展而不是零扩展。要做到这一点:

    cdq                 ;Set all bits in edx to the sign of eax
    xchg ebx,eax        ;eax = original ebx
    mov ecx,edx         ;ecx:ebx = original eax sign extended
    cdq                 ;edx:eax = original ebx sign extended

    add eax,ebx
    adc edx,ecx         ;edx:eax = eax + ebx

“可能更慢,具体取决于它是哪个 CPU”(见注)替代方法是通过向它们添加 0x80000000 来强制它们进入无符号整数的范围,然后通过从中减去 2*0x80000000(或 0x0000000100000000)来纠正结果。减 0x0000000100000000 和高 dword 减 1 一样,和高 dword 加 0xFFFFFFFF 一样,所以可以:

    add eax,0x80000000
    add ebx,0x80000000

    xor edx,edx         ;Set edx to zero
    add eax,ebx
    adc edx,0xFFFFFFFF  ;edx:eax = eax + 0x80000000 + ebx + 0x80000000 + (-0x0000000100000000)

注意:如果您关心性能;这种替代方法使您有机会将 0x80000000 添加到早期代码中的值(无论值来自何处),并且通常可以更快地结束(特别是如果多次使用相同的 32 位值,和/或如果添加可以免费并入其他计算)。

对于“混合类型”,您只需要将有符号值提升为 64 位。例如,如果 EAX 已签名而 EBX 未签名:

    cdq                 ;Set all bits in edx to the sign of eax
    add eax,ebx
    adc edx,0           ;edx:eax = eax + ebx

当然,对于较新的 CPU,您将使用 64 位代码。对于无符号 32 位值,默认情况下它们已经是零扩展的,您只需要一条add rax,rbx指令。对于已签名的号码,您可能需要签署扩展(如果您不能/没有事先签署扩展它们),例如:

    movsx rax,eax
    movsx rbx,ebx
    add rax,rbx
于 2013-11-12T23:06:23.107 回答
0

如果我正确理解了这个问题,您有两个 32 位整数相加,可能会给出一个 64 位整数。您想在没有 32 位溢出的情况下执行此操作。

看看编译器做了什么:

$ cat add64.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main (int argc, char **argv) {
    uint32_t a, b;

    a = strtoll(argv[1], NULL, 10);
    b = strtoll(argv[2], NULL, 10);
    printf("%lu + %lu = %llu\n", a, b, (uint64_t) a + b);
    return 0;
}
$ gcc -m32 -g -o add64 add64.c 
$ ./add64 3000000000 4000000000
3000000000 + 4000000000 = 7000000000
$ gcc -m32 -g -fverbose-asm -masm=intel -S add64.c
$ $EDITOR add64.s &
[5] 340
$

相关生成的程序集是:

    mov %ecx, DWORD PTR [%ebp-16]   # D.2300, a
    mov %ebx, 0 # D.2300,
    mov %eax, DWORD PTR [%ebp-12]   # D.2301, b
    mov %edx, 0 # D.2301,
    add %eax, %ecx  # D.2302, D.2300
    adc %edx, %ebx  # D.2302, D.2300
于 2013-11-12T22:48:32.437 回答
0

为了在 32 位机器上添加 64 位数字,您必须首先将 64 位数字的上半部分移动到寄存器 eax,然后将后半部分移动到 edx。操作此数字时,您必须跟踪该数字在 eax/edx 中的放置方式。

于 2013-11-12T22:51:34.063 回答