乘除運算指令
MUL
指令實現兩個無符號操作數的乘法運算。
乘數是OPRD,被乘數位于AL、AX或EAX中(由OPRD的尺寸決定,乘數和被乘數的尺寸一致)。
乘積尺寸翻倍:16位乘積送到AX;32位乘積送DX:AX;64位乘積送EDX:EAX。 操作數OPRD可以通用寄存器,可以存儲單元,但不能是立即數。
IMUL
有符號數乘法指令(sIgned MULtiply)
DIV
指令實現兩個無符號操作數的除法運算。
除數 (OPRD) 大小 | 被除數 | 商存放位置 | 余數存放位置 | 計算公式 |
---|---|---|---|---|
8位?(例如 BL) | AX?(16位) | AL | AH | AX / OPRD |
16位?(例如 BX) | DX:AX?(32位) | AX | DX | (DX:AX) / OPRD |
32位?(例如 EBX) | EDX:EAX?(64位) | EAX | EDX | (EDX:EAX) / OPRD |
商在AL、AX或者EAX中;余數在AH、DX或者EDX中(商和余數的尺寸與oprd相同)。 操作數OPRD可以是通用寄存器,可以是存儲單元,但不能是立即數。
IDIV
指令實現兩個有符號操作數的除法運算。
尺寸由除數OPRD決定。
操作數OPRD可以是通用寄存器,可以是存儲單元,但不能是立即數。
如果不能整除,余數的符號與被除數一致,而且余數的絕對值小于除數的絕對值。
符號擴展指令
指令把AL中的符號擴展到AH。
若AL的最高有效位為0,則AH=0;
若AL的最高有效位為1,則AH=FFH,也即AH的8位全都為1
指令把EAX中的符號擴展到EDX。
EAX的最高有效位為0,則EDX=0;
若EAX最高有效位為1,則EDX=FFFF FFFFH,也即EDX的32位全都為1。
指令把AX中的符號擴展到EAX的高16位。
AX的最高有效位為0,則EAX的高16位都為0;
若AX的最高有效位為1,則EAX的高16位都為1。
邏輯運算指令
處理器提供一組邏輯運算指令
否指令 ? ? ? ? ?NOT
按位取反
這是一個邏輯運算,而不是算術運算
最重要的“坑”:它不是求負數!
這是最需要理解的一點:
NOT
?指令不是求負數的指令!求一個數的負數(二進制補碼),正確的指令是?
NEG
。讓我們對比一下:
指令 操作 例子 (EDX = 10) 結果 (十進制) 解釋 NOT EDX
按位取反 NOT 10
-11 這是邏輯操作,不是算術操作。 NEG EDX
求負數 NEG 10
-10 這是算術操作,計算? 0 - EDX
與指令 ? ? ? ? ?AND
AND EAX, 3
?在功能上等價于?EAX % 4
(計算 EAX 除以 4 的余數)對EAX(設 1001)? 和3(0011),每位對應相乘? ,結果(0001)
X % 2?
?在功能上完全等價于?X & (2? - 1)
X % 4
X & 3
因為 4 是 22,而 3 = 4 - 1 = (22 - 1) X % 8
X & 7
因為 8 是 23,而 7 = 8 - 1 = (23 - 1) X % 16
X & 15
因為 16 是 2?,而 15 = 16 - 1 = (2? - 1)
或指令 ? ? ? ? ?OR
指令本身:
OR ECX, EDX
功能:這是按位或(Bitwise OR)?操作。
操作:它將?
ECX
?寄存器的每一位與?EDX
?寄存器的對應位進行“或”運算,并將結果存回?ECX
?寄存器。
ECX = ECX | EDX
規則:兩位中只要有一位是1,結果就是1。
0 OR 0 = 0
0 OR 1 = 1
1 OR 0 = 1
1 OR 1 = 1
異或指令 ? ? ?XOR
測試指令(TEST)
移位指令
移位計數:所有用寄存器指定次數的移位/循環移位指令(
SHL
,?SHR
,?SAR
,?ROL
,?ROR
,?RCL
,?RCR
),有且只能使用?CL
?寄存器來存放移位次數。
一般移位指令
算術左移指令 ? ?SAL(Shift Arithmetic Left)
邏輯左移指令 ? ?SHL(SHift logic Left)
算術右移指令 ? ?SAR(Shift Arithmetic Right)
?對于?y >> 4
?(右移)
這是關鍵所在!>>
?(右移) 的行為取決于?y
?的類型:
如果?
y
?是【無符號】類型 (例如?unsigned int
,?uint32_t
)y >> 4
?是?邏輯右移。高位補?
0
。
如果?
y
?是【有符號】類型 (例如?int
,?int32_t
)y >> 4
?是?算術右移。高位補?符號位(原來最高位的值,0或1)。這是為了保持負數的符號,實現“除以2的冪”的數學效果。
邏輯右移指令 ? ?SHR(SHift logic Right)
4者之間的比較
當右移兩位(或更多位)時,情況略有不同。
核心規則依然不變:CF始終保存的是【最后一次】移位操作所移出的那個比特位。
這意味著,如果一條指令移位N位(N>1),CPU實際上是在內部執行了N次單步移位。而CF在每一步都會被覆蓋,最終只保留最后一步(即第N次移位)?移出的那個位。
1.?
ADD EBX, 0
操作:
EBX + 0
,結果存回?EBX
。這相當于一個?NOP
(無操作),但它會根據結果設置標志位。結果:
EBX
?的值不變,仍是?7400EF9Ch
?(0111 0100 ...
)。標志位分析:
CF
?(進位標志): 加法沒有產生最高位的進位,所以?CF = 0
。
ZF
?(零標志): 結果不是零,所以?ZF = 0
。
SF
?(符號標志): 結果的最高位是?0
?(正數),所以?SF = 0
。
PF
?(奇偶標志): 計算結果的最低字節是?9Ch
?(1001 1100
)。數其中?1
?的個數:有?4
?個?1
(偶數個),所以?PF = 1
。你的注釋是正確的。
2.?
SHL EBX, 1
操作:將?
EBX
?的所有位向左移動1位。最高位(MSB)被移入?CF
,最低位(LSB)補?0
。計算前:?
EBX = 0111 0100 0000 0000 1110 1111 1001 1100
計算過程:
最高位?
0
?被移出,進入?CF
。所有位左移一位。
最低位補?
0
。計算后:?
EBX = 1110 1000 0000 0001 1101 1111 0011 1000
?(這就是?E801DF38h
)標志位分析:
CF
: 被移出的最高位是?0
,所以?CF = 0
。
ZF
: 結果?E801DF38h
?顯然不是零,所以?ZF = 0
。
SF
: 結果的新最高位現在是?1
(負數),所以?SF = 1
。
PF
: 計算結果的最低字節是?38h
?(0011 1000
)。數其中?1
?的個數:有?3
?個?1
(奇數個),所以?PF = 0
。你的注釋是正確的。
3.?
MOV CL, 3
?和?SHL EBX, CL
MOV CL, 3
:這只是一個數據傳送,不影響任何標志位。
SHL EBX, CL
:現在?CL = 3
,所以這條指令將?EBX
?邏輯左移3位。計算前:?
EBX = 1110 1000 0000 0001 1101 1111 0011 1000
?(E801DF38h
)計算過程:
相當于左移1位,重復3次。我們關注最后一次(第3次)移位移出的位,它決定?CF
。
第一次左移:移出最高位?
1
?-> (臨時CF=1), EBX變成?1101 0000 ...
第二次左移:移出新的最高位?
1
?-> (臨時CF=1), EBX變成?1010 0000 ...
第三次左移:移出新的最高位?
1
?->?這是最終決定CF的位。CF = 1
。
所有位左移3位后,最低3位補?000
。計算后:?
EBX = 0100 0000 0000 1110 1111 1001 1100 0000
?(這就是?400EF9C0h
)標志位分析:
CF
: 如上所述,最后一次移位移出的位是?1
,所以?CF = 1
。
ZF
: 結果?400EF9C0h
?不是零,所以?ZF = 0
。
SF
: 結果的最高位現在是?0
(正數),所以?SF = 0
。
PF
: 計算結果的最低字節是?C0h
?(1100 0000
)。數其中?1
?的個數:有?2
?個?1
(偶數個),所以?PF = 1
。