版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/scylhy/article/details/86351937
简单C语言及汇编过程
最近复习准备PaaS考试,看Docker部分的linux内核,突感兴许,之前看的unix高级
环境编程,也仅剩丁点记忆,故翻到网易云课堂上,老早想看,但始终未看的Linux
内核分析,打算放假回家把这部分结束了,现在就开个头吧。
看前觉得挺多,且无聊,学完一段后,还是挺有趣的~~
- code
int g(int x)
{
return x + 3;
}
int f(int x)
{
return g(x);
}
int main(void)
{
return f(8) + 1;
}
-
C语言生成可执行文件的过程
- 生成汇编代码
root@lhys:~/linuxcore# gcc main.c -S -o main.s root@lhys:~/linuxcore# cat main.s .file "main.c" .text .globl g .type g, @function g: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl %edi, -4(%rbp) movl -4(%rbp), %eax addl $3, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size g, .-g .globl f .type f, @function f: .LFB1: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $8, %rsp movl %edi, -4(%rbp) movl -4(%rbp), %eax movl %eax, %edi call g leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE1: .size f, .-f .globl main .type main, @function main: .LFB2: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl $8, %edi call f addl $1, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE2: .size main, .-main .ident "GCC: (Ubuntu 7.3.0-16ubuntu3) 7.3.0" .section .note.GNU-stack,"",@progbits root@lhys:~/linuxcore#
- 汇编
root@lhys:~/linuxcore# gcc -c main.s -o main.o root@lhys:~/linuxcore# ls main.c main.o main.s root@lhys:~/linuxcore# cat main.o ELF>@@ UH??}??E???]?UH??H??}??E??????UH????]?GCC: (Ubuntu 7.3.0-16ubuntu3) 7.3.0zRx J A?C RA?C NA?C ?? &main.cgfmain????????0 ???????? @`&.symtab.strtab.shstrtab.rela.text.data.bss.comment.note.GNU-stack.rela.eh_frame @980 &yy10y%:?O?J@hH ?Y root@lhys:~/linuxcore#
- 链接
root@lhys:~/linuxcore# gcc main.o root@lhys:~/linuxcore# ls a.out main.c main.o main.s root@lhys:~/linuxcore# ./a.out root@lhys:~/linuxcore#
-
c代码执行和汇编执行的过程分析
- 删除汇编代码中的辅助代码(.开头的信息)
g: pushq %rbp movq %rsp, %rbp //前两句生成空栈,即g的函数栈 movl %edi, -4(%rbp) movl -4(%rbp), %eax //eax寄存器默认存储返回值 addl $3, %eax popq %rbp //退回到g开始前的栈位置,即存eip的位置 ret //即popl $eip,程序计数器指向调用g的下一条指令位置 f: pushq %rbp movq %rsp, %rbp subq $8, %rsp movl %edi, -4(%rbp) movl -4(%rbp), %eax movl %eax, %edi call g //即pushl %eip,movl g $eip,保存下一条指令位置,并跳转到g leave //即movl $ebp %esp,popl %ebp,恢复到上一个栈区,并指向调用前存储的eip ret main: pushq %rbp movq %rsp, %rbp movl $8, %edi call f addl $1, %eax popq %rbp ret
- 执行过程演示图(来自网络,生成的汇编略有不同)