简体   繁体   中英

Why is my assembly code going into a infinite loop?

I am trying to make a for loop in assembly.

Here is what I am trying to achieve written in C:

#include <stdio.h>
int main(){
    for(int i = 0; i < 10; i++){
        printf("%d\n", i);
    }
    return 0;
}

This is what my assembly code looks like:

.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"

When I run this code, I get the current output:

0
2
2
2
2
2
2

and so on



Why is it that my code displays 0 first (as it should), and then two for an infinite amount of time? I hope my comments are accurate as this is what I think each line of code does.

Main doesn't allocate space on the stack for i, so the call to printf is overwriting i.

Add the instruction

sub $16, %rsp

right after

mov %rsp, %rbp

and add

add $16, %rsp

right before

pop %rbp

The reason to subtract 16 instead of 4 is to maintain stack alignment.

Instead of keeping i in the red-zone where it's clobbered by a call (see @prl's answer), keep i in a register .

It looks like you're following the (terrible) style of anti-optimized compiler output that stores everything to memory for debugging.

Save/restore rbx around your function and use ebx for i . (To maintain 16-byte stack alignment before the call _printf , don't make a stack frame because you don't need any stack space for locals.)

BTW, it's not wrong, but it's very unconventional to have some of the function body (your loop) before the function entry point. Your code is super overcomplicated in general. This is something like what you'd get from an optimizing compiler for your C function. (I didn't check on https://godbolt.org/ , but I'd recommend having a look.)

_main:                   #int main
    push  %rbx           # save RBX and realign the stack by 16

    xor   %ebx, %ebx
.loop:                    # do {
    mov   %ebx, %esi
    lea   _format(%rip), %rdi
    xor   %eax,%eax          # %al = 0 FP args in XMM registers
    call  _printf            # printf(format, i)

    inc   %ebx               # i++

    cmp   $10, %ebx
    jl  .loop             # }while(i<10)

    xor   %eax, %eax                 #return 0;
    pop   %rbx
    ret

 # Read-only data can go in .rodata
 # only mutable static data needs to go in .data
.section .rodata
  _format:    .asciz "%d\n"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM