x86 彙編/算術
所有算術指令都在(一個)ALU中執行。 ALU 只能執行整數運算,對於浮點運算指令,請參見“浮點”章節。
算術指令有兩個運算元:目標和源。
- 該目標必須是暫存器或記憶體位置。
- 該源可以是記憶體位置、暫存器或常數值。
注意,最多隻有一個運算元可以是記憶體位置。
| add addend, destination | GAS 語法 |
| add destination, addend | Intel 語法 |
這將 addend 新增到 destination,並將結果儲存在 destination 中。
| sub subtrahend, destination | GAS 語法 |
| sub destination, subtrahend | Intel 語法 |
與 add 相似,只是它從 destination 中減去 subtrahend。 在 C 中:destination -= subtrahend;
mul multiplicand
這將 multiplicand 乘以累加器中相應位元組長度的值。
| multiplicand 的寬度 | 1 位元組 | 2 位元組 | 4 位元組 | 8 位元組 |
| 相應的 multiplier | AL
|
AX
|
EAX
|
RAX
|
| product 高位部分儲存在 | AH
|
DX
|
EDX
|
RDX
|
| product 低位部分儲存在 | AL
|
AX
|
EAX
|
RAX
|
在第二種情況下,目標不是 EAX,這是為了與為舊處理器編寫的程式碼向後相容。
受影響的標誌是
- OF ≔ product 的高位部分 ≠ 0
- CF ≔ product 的高位部分 ≠ 0
所有其他標誌都未定義。
imul multiplicand
此指令幾乎與 mul 相同,但它對符號位(MSB)的處理不同。
該 imul 指令還接受其他兩種格式
| imul multiplicand, destination | GAS 語法 |
| imul destination, multiplicand | Intel 語法 |
這將 destination 乘以 multiplicand,並將結果(乘積)放入 destination 中。
| imul multiplicand, multiplier, product | GAS 語法 |
| imul product, multiplier, multiplicand | Intel 語法 |
這將 multiplier 乘以 multiplicand 並將其放入 product 中。
div divisor
這將被除數暫存器中的值除以 divisor,見下表。
idiv arg
與 div 相同,只是有符號。
| divisor 的寬度 | 1 位元組 | 2 位元組 | 4 位元組 | 8 位元組 |
| 被除數 | AX
|
DX ○ AX
|
EDX ○ EAX
|
RDX ○ RAX
|
| remainder 儲存在 | AH
|
DX
|
EDX
|
RDX
|
| quotient 儲存在 | AL
|
AX
|
EAX
|
RAX
|
圓圈(○)表示串聯。 對於除數大小為 4,這意味著 EDX 是輸入數字的位 32-63,EAX 是位 0-31(低位數字的權重較低,在本例中)。
由於通常對於有符號除法,輸入值通常是 32 位或 64 位,因此您通常需要使用CDQ 或CQO 在除法之前將 EAX 符號擴充套件到 EDX 或 RAX 到 RDX。
如果商不能放入商暫存器,則會發生算術溢位中斷。 運算後,所有標誌都處於未定義狀態。
neg arg
算術否定引數(即二進位制補碼否定)。
| adc src, dest | GAS 語法 |
| adc dest, src | Intel 語法 |
加帶進位。 將 src + CF 新增到 dest,將結果儲存在 dest 中。 通常在正常加法指令之後使用,以處理比暫存器大小大兩倍的值。 在以下示例中,source 包含一個 64 位數字,它將被新增到 destination 中。
mov eax, [source] ; read low 32 bits
mov edx, [source+4] ; read high 32 bits
add [destination], eax ; add low 32 bits
adc [destination+4], edx ; add high 32 bits, plus carry
| sbb src, dest | GAS 語法 |
| sbb dest, src | Intel 語法 |
減帶借位。 從 dest 中減去 src + CF,將結果儲存在 dest 中。 通常在正常減法指令之後使用,以處理比暫存器大小大兩倍的值。
inc augend
此指令將暫存器值 augend 增加 1。 它執行速度比 add arg, 1 快得多,但它不會影響 CF。
dec 被減數
將 被減數 中的值減 1,但這比語義上等效的 sub 被減數, 1 快得多。
被減數 可以是暫存器或記憶體運算元。
- 一些程式語言使用所有位為零或所有位設定為 1 來表示布林值。當您編寫布林函式時,需要考慮這一點。
dec指令可以幫助您做到這一點。通常,您根據標誌設定最終的(布林)結果。透過選擇一個與預期相反的指令,然後遞減結果值,您將獲得滿足程式語言要求的值。以下是一個測試零的簡單示例。如果您打算設定false,則“錯誤”設定的xor rax, rax ; rax ≔ false (ensure result is not wrong due to any residue) test rdi, rdi ; rdi ≟ 0 (ZF ≔ rax = 0) setnz al ; al ≔ ¬ZF dec rax ; rax ≔ rax − 1
1將透過dec“修復”。如果您打算設定true,則表示為 -1,您將遞減值為零,它的“下溢”將導致所有位翻轉。注意,一些架構執行dec緩慢,因為標誌暫存器僅被部分覆蓋。因此,使用neg通常更有效,儘管它也會影響 CF。setz al ; al ≔ ZF neg rax ; rax ≔ 0 − rax
- 由於
inc和dec不會影響 CF,您可以使用這些指令來更新迴圈的計數變數,而不會覆蓋其中儲存的一些資訊。如果您需要一個不影響任何標誌的指令,同時隱式地執行dec,您可以使用相當慢的loop。
lea 指令可用於算術運算,尤其是在指標上。請參閱 “資料傳輸”一章,§“載入有效地址”。