-1

32 ビット マシンで精度を落とさずに、つまり 64 ビットの「疑似レジスタ」で 2 つの 32 ビット数値を追加する方法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 ビット コードを使用します。add rax,rbx符号なしの 32 ビット値の場合、それらはデフォルトですでにゼロ拡張されており、必要な命令は 1 つだけです。署名された番号の場合、次のように拡張に署名する必要がある場合があります (事前に拡張に署名できない/しなかった場合)。

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

私が質問を正しく理解していれば、2 つの 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 に答える