【发布时间】:2011-09-04 11:43:25
【问题描述】:
我正在尝试自学 x86,因此我决定剖析一个简单的 c 程序并查看 GCC 的输出。程序是这样的:
#include <stdio.h>
int main() {
printf("%s","Hello World");
return 0;
}
我用 -S 编译了代码,然后去掉了我认为不必要的东西,并将汇编代码简化为这个。
.pfArg:
.string "%s"
.text
.Hello:
.string "Hello World"
.text
.globl main
.type main, @function
main:
pushq %rbp # push what was in base pointer onto stack
movq %rsp, %rbp # move stack pointer to base pointer
subq $16, %rsp # subtract 16 from sp and store in stack pointer
# prepare arguments for printf
movl $.Hello, %esi # put & of "Hello World" into %esi
movq $.pfArg, %rdi # put & of "%d" into %eax
call printf
leave
ret
现在上面代码中的几乎所有内容对我来说都是有意义的,除了 main 下的前两个。虽然这是我在不剥离东西的情况下得到的。
.LC0:
.string "%s"
.LC1:
.string "Hello World"
.text
.globl main
.type main, @function
main:
.LFB0:
pushq %rbp # push what was in base pointer onto stack
movq %rsp, %rbp # move stack pointer to base pointer
# prepare arguments for printf
movl $.LC0, %eax # put arg into %eax
movl $.LC1, %esi # put second arg into %esi
movq %rax, %rdi # move value in %rax to %rdi ???? ( why not just put $.LCO into %rax directly )
movl $0, %eax # clear out %eax ???? ( why do we need to clear it out )
call printf
movl $0, %eax # return 0
leave
ret
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
.section .note.GNU-stack,"",@progbits
我用 ??? 标记了 2 条说明我不明白。
第一条指令是将 %rax 中的内容移动到 %rdi 以准备 printf 调用。除了我们只是将 $.LC0(即字符串“%s”)移到 %eax 之外,这一切都很好。这似乎没有必要,为什么我们不首先将 $.LC0 移动到 %rdi 中,而不是将其移动到 %eax 中,然后再移动到 %rdi 中?
第二条指令是清除 %eax,我理解它是一个函数的返回值。但是,如果该函数无论如何都会破坏它,为什么 GCC 会关心清除它呢?
【问题讨论】:
-
看起来您使用的是 x86-64 编译器而不是 x86。
-
是的,你是对的,我忘了说。