HelloWorld:从 C 到 ASM 之旅

  C , ASM

这篇文章似乎有不少错误,有空再看心情改=。=

/* filename: helloworld.c */

#include <stdio.h>

int hello(int b) {
printf("Received: %d\n", b);
return b+333;
}

int main() {
int a=111, b=222;
printf("Passing arguments: %d, %d\n", a, b);
++a;
int c = hello(b);

return 444;
}
/* gcc -S helloworld.c -o helloworld.asm */
/* filename: helloworld.asm */

.file "helloworld.c"
.section .rdata,"dr"

LC0:
.ascii "Received: %d\12\0"
.text
.globl _hello
.def _hello; .scl 2; .type 32; .endef
_hello: hello 函数开始的地址
LFB10:
.cfi_startproc cfi stands for call frame information
for debugging purpose [1] [2]
pushl %ebp 保护 main() 的栈基
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp 重设栈基,新空栈 [3]
进入(stdcall, [4])函数后首先需要的步骤
.cfi_def_cfa_register 5
subl $24, %esp 我也不清楚为什么要拓展这么大的空间
movl 8(%ebp), %eax 8(%ebp) 就是传过来的 b
准备调用 printf()
movl %eax, 4(%esp) 先把第二个参数入栈
movl $LC0, (%esp) 再把第一个参数入栈,LC0 正好就是对应数据
call _printf 正式调用 printf()
movl 8(%ebp), %eax 准备好当前函数的 b(从内存中挪到寄存器)
addl $333, %eax b += 555
不用挪回内存,因为本函数已经不需要用到 b 了
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret 回到 main 函数
%eax 是约定好的放置函数返回值的地方 [4]
.cfi_endproc

LFE10:
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC1:
.ascii "Passing arguments: %d, %d\12\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB11:
.cfi_startproc
pushl %ebp 保护栈基
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp 重设栈基,新空栈
.cfi_def_cfa_register 5
andl $-16, %esp
subl $32, %esp
call ___main 我也不清楚这个 __main 是什么
movl $111, 28(%esp) 局部变量存在于栈中 [5]
movl $222, 24(%esp)
movl 24(%esp), %eax 参数开始入栈,从右到左 [4]
movl %eax, 8(%esp)
movl 28(%esp), %eax
movl %eax, 4(%esp)
movl $LC1, (%esp)
call _printf 正式调用 printf()
addl $1, 28(%esp) ++a
movl 24(%esp), %eax
movl %eax, (%esp) 这两行使参数 b 入栈
call _hello 调用 hello
gcc 自动给函数名前缀一个 _ 符号
这在 c++ 中有不同的规则
所以有些代码需要 extern "C"
movl %eax, 20(%esp) hello() 的返回值置于 %eax,入栈成为局部变量 c
movl $444, %eax 同样,%eax 放置函数返回值,main 也不例外
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE11:
.ident "GCC: (GNU) 5.3.0"
.def _printf; .scl 2; .type 32; .endef

Reference:

  1. In assembly code how .cfi directives work - An answer by @ysdx, Stackoverflow
  2. .cfi directives
  3. Call stack #Structure, wikipedia
  4. X86 调用约定 #stdcall, wikipedia
  5. C语言-内存管理基础, 简书