C代码:
#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
所以我试图提高我对x86汇编代码的理解。对于上面的代码,我标记了我认为我理解的内容。至于标记内容的问题,有人可以分享一些亮点吗?另外,如果我的任何评论都没有,请告诉我。
答案 0 :(得分:2)
andl $-16, %esp # ?
subl $32, %esp # ?
这会在堆栈上留出一些空间。首先,andl
指令将%esp
寄存器舍入到16字节的下一个最低倍数(练习:找出-16
的二进制值是什么来查看原因)。然后,subl
指令将堆栈指针向下移动一点(32字节),保留更多空间(下一步将使用它)。我怀疑这种舍入已经完成,因此通过%esp
寄存器进行访问会稍微提高效率(但是您必须检查处理器数据表以找出原因)。
movl $.LC0, (%esp) # point stack pointer to "hello" ?
这会将字符串"hello"
的地址放入堆栈(此指令不会更改%esp
寄存器本身的值)。显然,您的编译器认为将数据直接移动到堆栈更有效,而不是使用push
指令。