Loops 为什么我的汇编代码会进入无限循环?

Loops 为什么我的汇编代码会进入无限循环?,loops,for-loop,assembly,x86,Loops,For Loop,Assembly,X86,我试图在汇编中为循环创建一个 以下是我试图用C语言编写的内容: #包括 int main(){ 对于(int i=0;i

我试图在汇编中为循环创建一个

以下是我试图用C语言编写的内容:

#包括
int main(){
对于(int i=0;i<10;i++){
printf(“%d\n”,i);
}
返回0;
}
这就是我的汇编代码的样子:

.text
.globl _main


loop0.0:
  movl -4(%rbp), %eax           #eax = i
  cmpl $10, %eax                #compare i with 10
  jg loop0.2                    #if 10 > i goto loop0.2

loop0.1:
  leaq _format(%rip), %rdi      #set arg1 to format
  movl -4(%rbp), %esi           #set arg2 to i
  call _printf                  #printf(format, i)

  movl -4(%rbp), %esi           #set esi to i
  addl $1, %esi                 #esi++
  movl %esi, -4(%rbp)           #i = esi
  jmp loop0.0

_main:                           #int main
  pushq %rbp
  movq %rsp, %rbp

  movl $0, -4(%rbp)              #i = 0
  jmp loop0.0                    #goto  loop0.0
  loop0.2:

  xor %eax, %eax                 #return 0;

  popq %rbp
  retq


.data
  _format:
    .asciz "%d\n"
当我运行此代码时,我得到当前输出:

0
2
2
2
2
2
2
等等




为什么我的代码首先显示
0
(它应该显示),然后无限长时间显示两个?我希望我的评论是准确的,因为我认为每行代码都是这样做的。

Main没有在堆栈上为I分配空间,因此对printf的调用覆盖了I

添加说明

sub $16, %rsp
紧接着

mov %rsp, %rbp

add $16, %rsp
就在之前

pop %rbp

减去16而不是4的原因是为了保持堆栈对齐。

Main没有在堆栈上为i分配空间,因此对printf的调用覆盖了i

添加说明

sub $16, %rsp
紧接着

mov %rsp, %rbp

add $16, %rsp
就在之前

pop %rbp

减去16而不是4的原因是为了保持堆栈对齐。

而不是将
i
保留在被
调用
(参见@prl的答案)撞击的红色区域,
i
保留在寄存器中

看起来您正在遵循反优化编译器输出的(糟糕)风格,它将所有内容存储到内存中以进行调试

围绕您的功能保存/恢复
rbx
,并使用
ebx
进行
i
。(要在调用printf
之前保持16字节堆栈对齐,请不要制作堆栈帧,因为不需要任何用于局部变量的堆栈空间。)

顺便说一句,这没有错,但是在函数入口点之前有一些函数体(您的循环)是非常不传统的。您的代码通常是超级复杂的。这类似于从C函数的优化编译器中得到的结果。(我没有查看,但我建议您看一看。)

_main:#int main
按%rbx#保存rbx并将堆栈重新对齐16
异或%ebx,%ebx
.loop:#执行{
mov%ebx,%esi
lea _格式(%rip),%rdi
xor%eax,%eax#%al=0个XMM寄存器中的FP参数
调用_printf#printf(格式,i)
公司%ebx#i++
cmp$10%,ebx

jl.loop#}而(i而不是将
i
保留在被
调用
(参见@prl的答案)撞击的红色区域,
i
保留在寄存器中

看起来您正在遵循反优化编译器输出的(糟糕)风格,它将所有内容存储到内存中以进行调试

在函数周围保存/还原
rbx
,并对
i
使用
ebx
(要在
调用之前保持16字节堆栈对齐,请不要制作堆栈帧,因为不需要任何局部堆栈空间。)

顺便说一句,这没有错,但是在函数入口点之前有一些函数体(你的循环)是非常不传统的。你的代码通常是超级复杂的。这类似于你从优化编译器中得到的C函数。(我没有检查,但我建议你看一下。)

_main:#int main
按%rbx#保存rbx并将堆栈重新对齐16
异或%ebx,%ebx
.loop:#执行{
mov%ebx,%esi
lea _格式(%rip),%rdi
xor%eax,%eax#%al=0个XMM寄存器中的FP参数
调用_printf#printf(格式,i)
公司%ebx#i++
cmp$10%,ebx

jl.loop#}while(这是可行的。因为我还没有完全理解内存和堆栈是如何工作的,堆栈图是否有可能与答案相匹配?我还不知道如何编写它们。或者这是另一个问题?如果是的话,可以在StackOverflow上问它吗?如果你在这个论坛中搜索堆栈对齐,你会发现许多关于这个主题的问题和答案。希望其中的一个或多个能给您带来启发。我没有找到一个64位图表很好,但有一两个32位图表也不错。请务必注意哪些答案适用于64位,哪些适用于32位。主要思想适用于两者,但它们并不相同,我不想让您感到困惑。是吗这就是为什么之前你在最初的回答中说
sub$8
而不是
sub$16
?32位的
sub$8
,34位的
sub$16
?如果是这样的话,如果我开始编写自己的操作系统,以实模式加载(16位),我会
sub$4
?sub$8只是一个错误。(我希望我在别人看到它之前就把它修好了。)在32位的系统中,需要16字节对齐的系统使用sub$8,不需要16字节对齐的系统使用sub$4。之所以使用8,是因为eip和ebp都是4字节。这是可行的。因为我还不完全了解内存和堆栈是如何工作的,堆栈图有可能与答案一致吗?我还不知道如何编写它们。或者这是另一个问题n?如果是的话,可以在StackOverflow上提问吗?如果你在这个论坛中搜索堆栈对齐,你会发现很多关于这个主题的问题和答案。希望其中一个或多个问题能给你启发。我没有找到一个64位图很好,但有一两个32位图不错。一定要注意答案适用于64位,适用于32位。主要观点适用于两者,但它们并不相同,我不想让你感到困惑。这就是为什么你之前在初始答案中说
sub$8
而不是
sub$16
?32位的
sub$8
和34位的
sub$16
的原因吗?如果这是case,如果我开始编写自己的操作系统,以实模式(16位)加载,我会
sub$4
?sub$8只是一个错误