Assembly 补码运算
就像我们早些时候看到的,add指令执行加法操作,而sub指令的执行减法操作。在FLAGS寄存器中的两位能被这些指令设置,它们是:overflow(溢出位) 和carry flag(进位标志位)。如果操作的正确结果太大了以致于不匹配有符号数运算的目的操作数,溢出标志位将被置位。如果在加法中的最高有效位有一个进位或在减法中的最高有效位有一个借位,进位标志位将被置位。因此,它可以用来检查无符号数运算的溢出。进位标志位在有符号数运算中的使用将看起来非常简单。补码的一个最大的优点是加法和减法的规则实际上就与无符号整形的一样。因此,add和sub可以同时被用在有符号和无符号整形上。
这儿有一个进位产生,但是它不是结果的一部分。
这有两个不同的乘法和除法指令。
首先,使用MUL或IMUL 指令来进行乘法运算。MUL指令用于无符号数之间相乘,而IMUL指令用于有符号数之间相乘。为什么需要两个不同的指令呢?无符号数和有符号数补码的乘法规则是不同的。为什么会这样?考虑字节FF乘以它本身产生一个字的结果。使用无符号乘法这就是255乘上255,得65025 (或十六进制的FE01)。使用有
符号数乘法这就是¡1 乘上¡1,得1 (或十六进制的0001)。这儿有乘法指令的几种格式。最老的格式是像这样的:
mul source
source要么是一个寄存器,要么是一个指定的内存。它不可以是一个立即数。实际上,乘法怎么执行取决于源操作数的大小。如果操作数大小是一个字节,它乘以在AL寄存器中的字节,而结果被储存到了16位寄存器AX中。如果源操作数是16位,它乘以在AX中的字,而32位的结果被储存到了DX:AX。如果源操作数是32位的,它乘以在EAX中的数,而结果被储存到了EDX:EAX。
IMUL指令拥有与MUL指令相同的格式,但是同样增加了其它一些指令格式。这有两个和三个操作数的格式:
imul dest (目的操作数), source1(源操作数1)
imul dest (目的操作数), source1(源操作数1), source2(源操作数2)
表2.2展示可能的组合。
两个除法运算符是DIV和IDIV。它们分别执行无符号整形和有符号整形的除法。普遍的格式是:
div source如果源操作数为8位,那么AX就除以这个操作数。商储存在AL中,而余数储存在AH中。如果源操作数为16位,那么DX:AX就除以这个操作数。商储存在AX中,而余数储存在DX中。如果源操作数为32位,那么EDX:EAX就除以这个操作数,同时商储存在EAX中,余数储存在EDX中。IDIV 指令以同样的方法进行工作。这没有像IMUL指令一样的特殊的IDIV指令。如果商太大了,以致于不匹配它的寄存器,或除数为0,那么这个程序将被中断和中止。一个普遍的错误是在进行除法之前忘记了初始化DX或EDX。
NEG 指令通过计算它的单一的操作数补码来得到这个操作数的相反数。它的操作数可以是任意的8位,16位或32位寄存器或内存区域。