乘除运算指令
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 是 2²,而 3 = 4 - 1 = (2² - 1) X % 8
X & 7
因为 8 是 2³,而 7 = 8 - 1 = (2³ - 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
。