簡體   English   中英

在 32 位機器上添加 32 位數字,在兩個寄存器中擴展為 64 位和

[英]Adding 32-bit numbers on a 32 machine, widening to a 64-bit sum in two registers

如何在 32 位機器上添加幾個 32 位數字但沒有精度損失,即在 64 位“偽寄存器” eax:edx 使用英特爾語法匯編器。

假設您添加的 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和high dword減1是一樣的,和high 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

如果我正確理解了這個問題,您將有兩個 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

為了在 32 位機器上添加 64 位數字,您必須首先將 64 位數字的上半部分移入寄存器 eax,然后將下半部分移入 edx。 操作此數字時,您必須跟蹤該數字在 eax/edx 中的放置方式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM