从C代码了解x86汇编代码

时间:2012-03-10 23:57:45

标签: c assembly

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汇编代码的理解。对于上面的代码,我标记了我认为我理解的内容。至于标记内容的问题,有人可以分享一些亮点吗?另外,如果我的任何评论都没有,请告诉我。

1 个答案:

答案 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指令。