私は学んでおり、その過程でQWORDを多用するアセンブラー変換に取り組んでいます(x86-32ビット)。現在、私の参考資料には、これらの値を 32 ビット レジスタに分割するという明らかな範囲を超えて、そのような値を操作することについては何もありません。彼らは古い側にいると思います。新しいプロセッサには、mmx 命令や sse 命令などがあります。これを解決するための指示を調べてもよろしいでしょうか? QWORD値で作業を行うための最良の方法は何ですか?
2 に答える
64 ビット整数を扱うのは簡単かもしれませんし、そうでないかもしれません。実行する操作の種類によって異なります。
ブール演算 (AND、OR、XOT、NOT) の場合、任意の長さの整数を分割するだけで簡単に処理できます。
ADC
足し算と引き算では、 (Add With Carry) またはSBB
(Subtract With Borrow) 命令を連鎖させることで、任意の長さの整数を簡単にサポートできます。例 (128 ビット):
add eax,[value]
adc ebx,[value+4]
adc ecx,[value+8]
adc edx,[value+12] ;edx:ecx:ebx:eax = 128-bit result of addition
否定は単なる引き算 ( -x = 0 - x
) です。
SHLD
左/右にシフトする場合、連鎖またはSHRD
命令によって、任意の長さの整数を簡単にサポートできます。例 (128 ビット):
shld edx,ecx,12
shld ecx,ebx,12
shld ebx,eax,12
shl eax,12 ;edx:ecx:ebx:eax = 128-bit result of shift left by 12
シフト カウントが大きすぎる場合 (たとえば、左に 44 ビット シフトしたい場合)、最初にデータを移動してから、"元のカウント MOD 32" だけシフトする必要があります。例えば:
mov edx,ecx
mov ebx,ebx
mov ebx,eax
mov eax,0 ;edx:ecx:ebx:eax = original value shifted left by 32
shld edx,ecx,12
shld ecx,ebx,12
shld ebx,eax,12
shl eax,12 ;edx:ecx:ebx:eax = original value shifted left by 44
乗算の場合、CPU は「32 ビット * 32 ビット = 64 ビットの結果」をサポートします。それより大きいものについては、任意の幅の整数を任意の幅の整数で掛けることができます。これは、base4294967296 (各桁は 32 ビット整数) を使用することを除いて、base10 (各桁は 0 から 9 の値) を使用して大きな数を手で乗算する方法と似ています。たとえば、base10 を使用して 34 x 58 を倍数にするには、次のようにします。
result_digit0to1 = 4*8 = 32
result_digit1to2a = 4*5 = 20
result_digit1to2b = 3*8 = 24
result_digit2to3 = 3*5 = 15
result = result_digit0to1 + (result_digit1to2 + result_digit1to2) * 10 + result_digit2to3 * 100;
result = 32 + (20 + 24) * 10 + 15 * 100
result = 32 + 440 + 1500
result = 1972
基本的に、桁の位置/大きさを追跡しながら、一方の数値の各桁に他方の数値の各桁を掛けます。結果は中間結果の合計です。
「64 ビット * 64 ビット = 128 = ビットの結果」の場合は、次のようにします。
result_bits0to63 = first_bits0to31 * second_bits0to31;
result_bits32to95a = first_bits32to64 * second_bits0to31;
result_bits32to95b = first_bits0to31 * second_bits32to64;
result_bits64to128 = first_bits32to64 * second_bits32to64;
result = result_bits0to63 + ( (result_bits32to95a + result_bits32to95b) << 32) + (result_bits64to128 << 64)
ただし、これは符号なし整数に対してのみ機能します。符号付き整数の場合、符号ビットを削除して符号なし乗算を行い、その後結果に符号を設定する必要があります ( result_sign_bit = first_sign_bit XOR second_sign_bit
)。
除算については、「base2 long除算」を行うことになります。設定された最上位ビットを失うことなく、できる限り除数を左にシフトします (「シフトされたビット」を追跡しながら)。次に、分割された値と比較しながら、1ビットずつ元の位置に戻します。シフトされた除数が除算される値より小さい場合は、除算される値からシフトされた除数を減算し、結果に対応するビットを設定します。除数が元の位置に戻った後、除算された値は剰余になります。
乗算と同様に、除算は実際には符号なし整数に対してのみ機能し、事前に符号ビットを削除してから、符号なし除算を実行してから、(結果と剰余の両方で) 符号を設定する必要があります。
このすべてを理解している場合。そうすれば、(たとえば) 64 ビット CPU で 512 ビットの計算を実行したり、16 ビット CPU で 65536 ビットの計算を実行したり、任意の CPU で「任意の幅」の計算を実行したりできます。
最善の方法は、コースで明示的に禁止されていない限り、QWORD で動作する命令を使用することです。次に、あなたが述べたように、32ビットレジスタを使用して作業を行う必要があります。QWORD を使用して基本的な論理命令を実行するサブルーチンをいくつか作成できます。