【版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途】
这一节介绍如何在编语言中上使用整数运算,包括加法、减法、乘法和除法。
add src, dest
其中src可以是立即数值、内存地址、寄存器。dest可以是寄存器或内存中的值,不能同时使用内存地址作为源和目标。结果存放在dest中。和其他GNU汇编指令一样,需要在add结尾添加b、w、l来指定操作数长度。如果没有使用整个寄存器,就要确保零填充目标寄存器,使得寄存器高位没有内容。add指令可以对所有带符号的整数执行加法操作。
在执行整数想加时,应该注意EFLAGS寄存器,当在无符号数做加法操作造成进位(结果大于允许的最大值)情况时,进位标志会被置为1。在有符号整数出现溢出情况时(结果小于允许最小负值或大于允许最大正值),溢出标志会被设置为1。下面示例演示无符号整数加法进位的情况:
<span style="font-family:Microsoft YaHei;">#add1.s
.section .text
.globl _start
_start:
nop
movl $0, %ebx
movb $240, %bl
movb $20, %al
# movb $2, %al
addb %al, %bl
jc over
movl $1, %eax
int $0x80
over:
movl $1, %eax
movl $0, %ebx
int $0x80</span>
如果加法操作造成进位,则把进位标志设置为1,程序返回0,否则返回加法的结果。我们分别修改上述代码使其造成进位和不进位(取消代码注释行且注释上一行代码),分别make、执行结果如下:
<span style="font-family:Microsoft YaHei;">$ make
as -o add1.o add1.s --gstabs
ld -o add add1.o
$ ./add
$ echo $?
0
$ vim add1.s//修改代码,使其不进位
$ make clean;make
rm -f add1.o add *~
as -o add1.o add1.s --gstabs
ld -o add add1.o
$ ./add
$ echo $?
242 //不进位时程序返回加法结果
</span>
在执行无符号整数加法时,总应该检查进位标志,如果知道输入值界限,就可以不必检查进位标志。
在处理有符号整数,不需要判断进位标志,而是需要注意溢出标志,当结果溢出正值或负值界限时,这个标志会被设置为1。
使用adc指令可以处理大于双字数据长度的加法。
减法操作和加法操作类似,减法指令是sub,格式类似加法指令:
sub src, dest
减法指令也需要在sub末尾添加b、w、l。和add指令类似,sub指令也会修改EFLAGS寄存器的位。
使用进位标志确定无符号整数减法产生负数结果的情况。有符号数的减法需要依靠溢出标志来判断数据长度界限的情况。
sbb指令类似adc指令,可以使用进位情况帮助执行大的无符号整数的减法操作。
inc指令和dec指令可分别对无符号整数值进行递增和递减操作。这两个指令不会影响进位标志。指令格式如下:
dec dest
inc dest
dest可以是8位、16位、32位寄存器和内存中的值。
mul src
src可以是8、16、32位寄存器或内存值。使用GNU汇编器时,命令助记符结尾加上正确长度字符。该指令的目标操作数是隐含的。根据元操作数的值长度,乘法操作使用另一个操作数必须放在al、ax、eax寄存器中。由于乘法可能产生很大的值,所以mul指令目标位置必须是元操作数的两倍长度。下表是无符号整数乘法的需求:
源操作数长度(位) |
目标操作数
|
目标位置
|
8
|
AL
|
AX
|
16
|
AX
|
DX:AX
|
32
|
EAX
|
EDX:EAX
|
imul命令可以进行有符号整数的乘法。 imul指令有三种指令格式:
imul src #这种指令格式和mul的使用一样
imul src,dest #允许指定eax之外的目标操作数
imul multipler, src, dest #multipler是立即值
有符号除法指令:idiv divisor
divisor是隐含被除数要除以的值。
在平时编写高级语言时,都知道乘法和除法是很消耗处理器时间的,有些时候会使用移位来代替乘除法。在汇编语言中一样,也可以使用移位,移位指令提供基于2的乘方的乘法和除法。把二进制数字左移1就是乘以2,左移2位就是乘以4,移位操作比执行二进制乘法操作要快得多。
向左移位命令:sal(算数左移)和shl(逻辑左移),这两个指令执行相同操作。有3种格式:
sal dest #左移一位,等同于乘以2
sal %cl, dest #左移cl寄存器中的数
sal shifter, dest #左移shifter值指定的数
左移指令可以对无符号和有符号整数执行向左移位指令,空位补0,超出数据长度的位首先存放在进位标志中,在下一次移位操作中被丢弃。
向右移位指令:shr和sar
shr对无符号整数进行移位操作,右移位产生的空位用0填充。
sar指令根据整数符号位来判断移位产生的空位的填充数,负数空位填1,正数空位填0。
右移位移出的数据元素首先被移动到进位标志,然后再移出去,这里和左移一样。
and、or、xor指令格式一样:
and src, dest
not指令使用单一操作数。
清空寄存器最高效的方式就是使用xor指令对寄存器和他本身进行异或操作。
位测试指令:test src, dest
test指令最常见的用途是检查EFLAGS寄存器中的标志。