透过汇编代码来理解计算机的工作
2015-03-08 13:34 zfunction 阅读(105) 评论(0) 收藏 举报发表本博客的目的是要完成《Linux内核分析》课程布置的实验,同时也为自己的学习做一个梳理和总结。如有疏漏和错误,敬请指正!
实验环境为实验楼64位Linux虚拟机,实验代码为一个简单的C程序生成的32位汇编代码。C源代码(main.c)如下:
1 int g(int x) 2 { 3 return x + 2; 4 } 5 6 int f(int x) 7 { 8 return g(x); 9 } 10 11 int main(void) 12 { 13 return f(3) + 5; 14 }

通过命令:
gcc –S –o main.s main.c -m32
获得32位汇编代码(main.s):
1 .file "main.c" 2 .text 3 .globl g 4 .type g, @function 5 g: 6 .LFB0: 7 .cfi_startproc 8 pushl %ebp 9 .cfi_def_cfa_offset 8 10 .cfi_offset 5, -8 11 movl %esp, %ebp 12 .cfi_def_cfa_register 5 13 movl 8(%ebp), %eax 14 addl $3, %eax 15 popl %ebp 16 .cfi_restore 5 17 .cfi_def_cfa 4, 4 18 ret 19 .cfi_endproc 20 .LFE0: 21 .size g, .-g 22 .globl f 23 .type f, @function 24 f: 25 .LFB1: 26 .cfi_startproc 27 pushl %ebp 28 .cfi_def_cfa_offset 8 29 .cfi_offset 5, -8 30 movl %esp, %ebp 31 .cfi_def_cfa_register 5 32 subl $4, %esp 33 movl 8(%ebp), %eax 34 movl %eax, (%esp) 35 call g 36 leave 37 .cfi_restore 5 38 .cfi_def_cfa 4, 4 39 ret 40 .cfi_endproc 41 .LFE1: 42 .size f, .-f 43 .globl main 44 .type main, @function 45 main: 46 .LFB2: 47 .cfi_startproc 48 pushl %ebp 49 .cfi_def_cfa_offset 8 50 .cfi_offset 5, -8 51 movl %esp, %ebp 52 .cfi_def_cfa_register 5 53 subl $4, %esp 54 movl $8, (%esp) 55 call f 56 addl $1, %eax 57 leave 58 .cfi_restore 5 59 .cfi_def_cfa 4, 4 60 ret 61 .cfi_endproc 62 .LFE2: 63 .size main, .-main 64 .ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2" 65 .section .note.GNU-stack,"",@progbits
可以发现main.c生成的main.s汇编代码多而杂,但是凡是以"."开头的行都是一些辅助消息,暂且将其看作是注释好了。我们可以将其都删掉,于是有简化后的代码(main.s):
1 g: 2 pushl %ebp 3 movl %esp, %ebp 4 movl 8(%ebp), %eax 5 addl $2, %eax 6 popl %ebp 7 ret 8 f: 9 pushl %ebp 10 movl %esp, %ebp 11 subl $4, %esp 12 movl 8(%ebp), %eax 13 movl %eax, (%esp) 14 call g 15 leave 16 ret 17 main: 18 pushl %ebp 19 movl %esp, %ebp 20 subl $4, %esp 21 movl $3, (%esp) 22 call f 23 addl $5, %eax 24 leave 25 ret
现在对此汇编代码进行具体分析,可见每个C函数生成的汇编代码都维护有一个自己的堆栈,而堆栈之间也随着函数的调用而相互嵌套的。
g:
pushl %ebp #接下来的两行指令建立被调函数的堆栈
movl %esp, %ebp #
movl 8(%ebp), %eax # 接下来的两条指令实现3+2的加法运算
addl $2, %eax #
popl %ebp #恢复调用函数的堆栈
ret #返回调用函数的下一条指令
f:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call g
leave
ret
main:
pushl %ebp
movl %esp, %ebp
subl $4, %esp # #1
movl $3, (%esp)
call f
addl $5, %eax
leave
ret
吴厚洲 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
浙公网安备 33010602011771号