Linux汇编之循环

汇编 2015年03月11日 ,

Linux汇编循环指令

循环是改变程序内指令路径的另外一种方式。循环可以使用单一循环函数编写重复性任务的代码。

本文中枫竹梦介绍Linux汇编语言(ASM)中的循环指令,并给出相应汇编语言程序的例子。

循环指令

前的介绍中曾使用跳转指令和递减寄存器值创建一个循环。更简单的方式是使用循环指令。

循环指令使用ECX寄存器作为计数器并且随着循环指令的执行,自动递减它的值。循环指令有如下内容。

指令 描述
LOOP 循环直到ECX寄存为零
LOOPE/LOOPZ 循环直到ECX寄存器为零,或者没有设置ZF标志
LOOPNE/LOOPNZ 循环直到ECX寄存器为零,或者设置ZF标志

在上表中,后两组指令提供了监视零标志的附加功能。指令格式如下:

loop address

其中address是要跳转到的程序代码位置的标签名称。不幸的是,循环指令只支持8位偏移量,所以只能进行短跳转。

循环开始前,需要在ECX寄存器中设置执行迭代的次数值。常使用如下方式:

< 在循环之前的其他代码 >
movl $100, %ecx
loop1:
< 需要循环的代码 >
loop loop1
< 循环之后要执行的代码 >

如果循环内的指令修改了ECX寄存器的值,循环就是会影响。特别是在循环内调用其他函数时,更要特别注意。循环的好处是它自动递减ECX寄存器的值,而不影响EFLAGS寄存器的标志位。

循环范例

下面是一个求1到100的整数的和的程序,演示如何使用LOOP指令:

# loop.s - By furzoom @ Mar 8, 2015
.section .data
output:
.asciz "The value is: %d\n"
.section .text
.globl _start
_start:
movl $100, %ecx
movl $0, %eax
loop1:
addl %ecx, %eax
loop loop1
pushl %eax
pushl $output
call printf
addl $8, %esp
movl $1, %eax
movl $0, %ebx
int $0x80

运行结果如下:

[mn@furzoom asm]$ as -o loop.o loop.s
[mn@furzoom asm]$ ld -dynamic-linker /lib/ld-linux.so.2 -lc -o loop loop.o
[mn@furzoom asm]$ ./loop
The value is: 5050
[mn@furzoom asm]$

LOOP指令灾难

如果在上面的例子中将ECX寄存器的值初始化为0,会有什么样的结果呢?运行结果如下:

[mn@furzoom asm]$ as -o loop2.o loop2.s
[mn@furzoom asm]$ ld -dynamic-linker /lib/ld-linux.so.2 -lc -o loop2 loop2.o
[mn@furzoom asm]$ ./loop2
The value is: -2147483648
[mn@furzoom asm]$

显示这样的结果是不正确的。原因在于当执行LOOP指令时,它首先将ECX寄存器中的值递减1,然后检查ECX中的值是否为0。那么当ECX寄存器初始化为0时,执行LOOP指令时,先将ECX寄存器中的值减1,使它为-1。因为这个值不是零,所以LOOP指令继续执行下去,循环回到定义的标签。该循环会在寄存器溢出时退出,并且显示错误的值。

为也纠正这个问题,需要检查ECX寄存器包含零值的特殊条件。幸运的是,Intel提供了专门用于这个目的的指令。JCXZ指令就是当ECX寄存器为0时进行的分支指令。程序修改如下:

# betterloop.s - By furzoom @ Mar 8, 2015
.section .data
output:
.asciz "The value is: %d\n"
.section .text
.globl _start
_start:
movl $0, %ecx
movl $0, %eax
jcxz done
loop1:
addl %ecx, %eax
loop loop1
done:
pushl %eax
pushl $output
call printf
addl $8, %esp
movl $1, %eax
movl $0, %ebx
int $0x80

在程序的循环开始外增加了JCXZ指令,如果ECX寄存器的值为0,则不进行循环,直接输出。运行结果如下:

[mn@furzoom asm]$ as -o betterloop.o betterloop.s
[mn@furzoom asm]$ ld -dynamic-linker /lib/ld-linux.so.2 -lc -o betterloop betterloop.o
[mn@furzoom asm]$ ./betterloop
The value is: 0
[mn@furzoom asm]$

结果正如期望的那样。这样枫竹梦就把汇编语言的循环指令介绍完了。

(完)

如无特别说明,本站文章皆为原创,若要转载,务必请注明以下原文信息:
日志标题:《Linux汇编之循环》
日志链接:http://furzoom.com/linux-asm-loop/
博客名称:枫竹梦

发表评论

插入图片

NOTICE1:请申请gravatar头像,没有头像的评论可能不会被回复!

回到顶部