x86-64汇编程序中的无限循环

时间:2013-11-07 17:27:51

标签: c++ c gcc assembly x86-64

#include <stdio.h>
#include <math.h>

int main(int argc, const char *argv[])
{
  long i, max;
  long sum = 0;
  max = (long)pow(2,32);

  for (i = 0; i < max; i++) {
    sum += i; 
  }
  printf("%ld\n", sum);
  return 0;
}

$gcc -S main.c

问题是:在下面的.L2代码中,-8(%rbp)始终等于零,%rax始终大于零。那么这是一个无限循环?如果我使用gcc -S -O1 main.c进行编译,则非常清楚。我真的很困扰!

汇编代码的一小部分:

main:   
    pushq   %rbp
    movq    %rsp, %rbp
    subq    $48, %rsp
    movl    %edi, -36(%rbp)
    movq    %rsi, -48(%rbp)
    movq    $0, -16(%rbp)
    movl    $0, -8(%rbp)
    movl    $2, -4(%rbp)
    movq    $0, -24(%rbp)
    jmp .L2

.L3:
    movq    -24(%rbp), %rax
    addq    %rax, -16(%rbp)
    addq    $1, -24(%rbp)

.L2:
    movq    -24(%rbp), %rax     
    cmpq    -8(%rbp), %rax       
    jl  .L3                      

.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"

2 个答案:

答案 0 :(得分:2)

真实循环计数器(i)位于-24(%rbp)。在第三行,它增加了。在第4行,它被加载到rax。因此rax不是常数零,它与i一起贯穿值。

-8(%rbp),假设是max。所以将i的值与之进行比较,这就是你的循环退出条件。 -8(%rbp)不应为零。如果是,我闻到流氓32位算术。

编辑:我想我知道是怎么回事。常量2和32是int,而不是long,因此假定为32位。 int的大小取决于平台;甚至海湾合作委员会的公约也许会有所不pow(int, int)被实现为内在的。参数为32位时,2 ^ 32为0。

替换

max = (long)pow(2,32);

max = pow(2l, 32l);

或者使用常数更好:

max = 0x100000000l;

就像我和其他人所怀疑的那样,混合中有一块32位。

答案 1 :(得分:1)

不,它不是无限循环。首先,%rax并不总是大于0,在该行中它从-24(%rbp)获得值,这显然是变量i。当它进入循环时,它将-24(%rbp)设置为零,然后跳转到.L2它发生在您未显示的部分。如果-{(%rbp)是变量max的值等于零(在溢出的情况下)jl将不会跳转到.L3并且循环将在首次检查后终止。 我不太明白为什么你需要为此阅读汇编,这在C ++源代码中非常明显。