Reputation:
C code:
#include <stdio.h>
main() {
int i;
for (i = 0; i < 10; i++) {
printf("%s\n", "hello");
}
}
ASM:
.file "simple_loop.c"
.section .rodata
.LC0:
.string "hello"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushl %ebp # push ebp onto stack
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp # setup base pointer or stack ?
.cfi_def_cfa_register 5
andl $-16, %esp # ?
subl $32, %esp # ?
movl $0, 28(%esp) # i = 0
jmp .L2
.L3:
movl $.LC0, (%esp) # point stack pointer to "hello" ?
call puts # print "hello"
addl $1, 28(%esp) # i++
.L2:
cmpl $9, 28(%esp) # if i < 9
jle .L3 # goto l3
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
So I am trying to improve my understanding of x86 assembly code. For the above code, I marked off what I believe I understand. As for the question marked content, could someone share some light? Also, if any of my comments are off, please let me know.
Upvotes: 3
Views: 934
Reputation: 994351
andl $-16, %esp # ?
subl $32, %esp # ?
This reserves some space on the stack. First, the andl
instruction rounds the %esp
register down to the next lowest multiple of 16 bytes (exercise: find out what the binary value of -16
is to see why). Then, the subl
instruction moves the stack pointer down a bit further (32 bytes), reserving some more space (which it will use next). I suspect this rounding is done so that access through the %esp
register is slightly more efficient (but you'd have to inspect your processor data sheets to figure out why).
movl $.LC0, (%esp) # point stack pointer to "hello" ?
This places the address of the string "hello"
onto the stack (this instruction doesn't change the value of the %esp
register itself). Apparently your compiler considers it more efficient to move data onto the stack directly, rather than to use the push
instruction.
Upvotes: 2