linux平台学x86汇编(十):整数运算

【版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途】
这一节介绍如何在编语言中上使用整数运算,包括加法、减法、乘法和除法。
  • 加法指令
        add指令用于把两个整数想加。格式如下:
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指令用于两个无符号整数相乘,格式如下:
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是立即值
  • 除法指令
无符号除法指令:div divisor
有符号除法指令: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。
右移位移出的数据元素首先被移动到进位标志,然后再移出去,这里和左移一样。
  • 逻辑操作指令
布尔逻辑操作:add、not、or、xor
and、or、xor指令格式一样:
and src, dest
not指令使用单一操作数。
清空寄存器最高效的方式就是使用xor指令对寄存器和他本身进行异或操作。

位测试指令:test src, dest
test指令最常见的用途是检查EFLAGS寄存器中的标志。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。