32 ビット マシンで精度を落とさずに、つまり 64 ビットの「疑似レジスタ」で 2 つの 32 ビット数値を追加する方法eax:edx
。Intel 構文アセンブラを使用します。
3 に答える
追加する 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
私が質問を正しく理解していれば、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
32 ビット マシンで 64 ビット数値を追加するには、最初に 64 ビット数値の上半分をレジスタ eax に移動し、次に後半を edx に移動する必要があります。この数値を操作するときは、数値が eax/edx にどのように配置されたかを追跡する必要があります。