Reputation: 6547
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.
Upvotes: 0
Views: 700
Reputation: 363980
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"
Upvotes: 2
Reputation: 12435
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.
Upvotes: 3