AT&T 汇编-6: 循环

loop 指令使用 ecx 作为计数器并且在每次执行的时候自动递减 ecx 的值,直到 ecx 为 0。loop 指令的格式是

loop location

其中 location 是要跳转的程序代码的标签。loop 指令只支持 8 位的偏移量,所以只能进行短跳转(跳转偏移量小于 128 字节)。

# loop.s

.section .rodata
msg:
   .asciz   "The value of ecx is %d.\n"

.section .text
.globl main
main:
   movl  $5,   %ecx
loop1:
   pushl %ecx
   pushl $msg
   call  printf
   addl  $4,   %esp
   popl  %ecx
   loop  loop1

   pushl $0
   call  exit

第 12-14 行打印每次循环开始时 ecx 的值。因为调用 printf() 的时候会修改 ecx 的值(具体为什么修改还不清楚……),所以调用完后在 16 行把栈中恢复调用前保存的 ecx 的值。

这个程序的输出是

The value of ecx is 5.
The value of ecx is 4.
The value of ecx is 3.
The value of ecx is 2.
The value of ecx is 1.

可以看到 ecx 为 0 的时候并没有打印而是跳出了循环,而 loop 指令是在 ecx 为 0 的时候不执行跳转,也就是说执行第 17 行代码时是先把 ecx 的值减 1,再判断 ecx 是否为 0。

因为 loop 指令是先递减 ecx 的值再判断 ecx 是否为 0,所以如果 ecx 初始值为 0 的时候,执行 loop 指令将会使 ecx 的值变为 -1,从而 ecx 不为 0 而执行循环。因此在进入循环前可以使用指令 jcxz 判断 ecx 是否为 0。

另外也可以使用 cmp 和跳转指令的组合来模拟循环,只是在执行对 ecx 的减法操作时如果 ecx 为 0 会设置 ZF 标志,而 loop 指令在递减 ecx 的值为 0 的时候不会设置 ZF 标志。

# cmp-jnz.s

.section .rodata
msg:
   .asciz   "The value of ecx is %d.\n"

.section .text
.globl main
main:
   movl  $5,   %ecx
loop1:
   pushl %ecx
   pushl $msg
   call  printf
   addl  $4,   %esp
   popl  %ecx
   subl  $1,   %ecx
   jnz   loop1

   pushl $0
   call  exit
发表于 2011年5月19日
本文目前尚无任何评论.

发表评论

XHTML: 您可以使用这些标签: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>