6.1 整数演算命令#
ADD#
ADD A,B
命令は B の値を A に加え、結果を A に保存します。A はレジスタまたはメモリ値であることができます。B はレジスタ、定数、またはメモリ値であることができます。同じ命令内では、A と B は同時にメモリ値にすることはできません。
add テキストの検索結果
上の図では、多くの ADD 命令の例があります。これらの例では、最初のオペランドはレジスタであり、2 番目のオペランドは定数です。したがって、プログラム実行時には、定数とレジスタの値を加算した結果がそのレジスタに保存されます。
例 1 レジスタに定数を加算
上の図では、ECX = 10000
の場合、定数 4 を加えると結果は 10004 になり、結果がECX
に再保存されます。
例 2 メモリ値に定数を加算
上の図では、ADD 命令はECX+30
で指定されたアドレスに格納されている値に定数0xffffffff
を加算します。プログラムがこのアドレスに書き込み権限を持っている場合、計算結果も同じアドレスに保存されます。ECX = 0x10000
と仮定すると、30 を加えると0x10030
になります。このアドレスに保存されている数が 1 である場合、定数0xffffffff
を加えると - 1 になり、結果は 0 になり、0x10030
のアドレスに保存されます。
例 3 レジスタの加算
上の図では、2 つのレジスタの加算結果が eax に保存されます。ADD 命令は 16 ビットおよび 8 ビットレジスタにも適用できます。
例えば:
ADD AL,8
ADD AX,8
ADD BX,AX
ADD byte ptr ds: [EAX],7 # EAXが指すバイトに7を加え、同じアドレスに保存します。
ADD 命令のオペランドでは、A が定数でない限り、または A と B がメモリ値の場合、他のレジスタやメモリの組み合わせはすべて許可されています。
SUB#
SUB A,B
命令はADD
命令と同じですが、2 つのオペランドを引き算し、最終結果を A に保存します。SUB で許可されるオペランドの組み合わせは ADD と同じです。
例 1 sub の検索結果
INC & DEC#
INC A
およびDEC A
命令は、レジスタまたはメモリ値を ±1 します。これは加算および減算の特殊なケースです。通常、これらの命令はカウンタを ±1 するために使用されます。
IMUL#
IMUL は符号付き整数乗算命令であり、2 つの使用方法があります。
IMUL A,B
およびIMUL A,B,C
- 最初の方法は A と B を掛けて、結果を A に返します。
- 2 番目の方法は B と C を掛けて、結果を A に返します。
これらの 2 つの方法では、A はレジスタである必要があり、B はレジスタまたはメモリ値(最初の方法では定数でも可能)、C は定数である必要があります。
例:
Imul eax, [ecx]
Imul esi, edi, 25
例 1 imul の使用例
上記の例では、1 つの使用方法のみが示されており、2 つのオペランドを掛け合わせて最初のオペランドに結果を保存します。
IDIV#
IDIV A
命令では、除数のみが指定されます。被除数は指定されていませんが、保存先は固定されています。
Dividend (D) ➗ divider (d) = quotient (q)
Dividend (D) は被除数、divider (d) は除数、quotient (q) は除算の結果であり、商です。
32 ビット演算では、EDX と EAX は 64 ビットの数を構成し、EDX が上位ビット、EAX が下位ビットになります。この 64 ビットの数を A で除算すると、商が EAX に返され、余りが EDX に返されます。
例 1 IDIV の使用例
上の図では、EAX=5、EDX=0、ECX=2 の場合、5➗2 の結果は 2 で、EAX に保存され、余り 1 が EDX に保存されます。
A がメモリ値である場合も同様で、EDXが A で除算され、商が EAX に返され、余りが EDX に返されます。
6.2 論理演算命令#
最初に AND(ビットごとの論理積)、OR(ビットごとの論理和)、XOR(排他的論理和)演算があります。
AND A,B は A と B に対して AND 演算を行い、最終結果を A に保存します。OR と XOR 演算も同様です。
A と B はレジスタまたはメモリ値であることができますが、同じ命令内では A と B が両方ともメモリ値であることは許可されません。
XOR#
最も一般的な例は同じレジスタに対する XOR(排他的論理和)演算であり、その値をゼロにします。例えば、XOR EAX,EAX
や他のレジスタをゼロにすることができます。XOR(排他的論理和)演算の真理値表は上の図に示されています。同じ数に対して XOR 演算を行うと、結果は 0 になります。操作は 2 進数モードで行われます。
16 進数でも XOR 演算を行うことができ、Python では^
記号で XOR を表します。2 つの同じ値を XOR すると、最終結果は 0 になります。
AND#
and eax,0xf
0xf は 2 進数で 1111 を表します。
0xf の下位 4 ビットは 1 なので、eax の下位 4 ビットは変わらず、他のビットはすべて 0 になります。この方法により、eax の下位 4 ビットが残り、他のビットがクリアされます。
Python では、AND 演算は&
記号で表され、上の図の結果は 0b111、つまり最下位の 4 ビットです。
OR#
OR 演算は Python では|
記号で表されます。
NOT#
NOT A
は A のすべてのビットを反転させ、A に保存します。Python ではビットごとの反転は~
記号で行われます。0101 の場合、各ビットが反転されます。すべての 0 は 1 に反転し、すべての 1 は 0 に反転します。
例 1 0b0101 の反転
例 2 結果は 0b1010
NEG#
NEG A
は A を - A に変換します。NEG 演算はビットごとの反転とは異なり、ビットごとの反転に 1 を引いています。
Python では、NEG を使用して反転後に 1 を加えることができます。
SHL#
SHL A,B
SHR A,B では、A はレジスタまたはメモリ値であり、B は定数または 8 ビットレジスタです。これらの命令はオペランドをビット単位で左または右にシフトし、欠けたビットは 0 で埋めます。例えば、-1 を考えてみましょう。
例 1 -1 の 2 進数表現
SHL 2 を実行すると、次の図のようになります。
これらのビットを左にシフトすると、左端の 2 つのビットが破棄され、右側の 2 つのビットが 0 で埋められます。
SHR の場合も同様で、これらのビットを右にシフトし、右側のビットが破棄され、左側の空き領域が 0 で埋められます。
また、ROL と ROR という 2 つの類似した命令もあります。これらの命令は各ビットを一定の位置に移動しますが、一方の端が他方の端に戻ると、命令は各ビットのシフトを行いますが、内容は変更しません。
この章では、アセンブリ言語の整数演算および論理演算命令について説明しました。基礎を固めるために役立ちます。