反汇编一个简单的C

来源:互联网 发布:中国十大禁菜 知乎 编辑:程序博客网 时间:2024/06/08 14:24

朱婷婷 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

计算机是怎么工作的?

我们知道计算机基本都是采用的冯诺依曼体系结构,它主要的核心思想就是存储程序计算机,指令和数据不加区别混合存储在同一个存储器中。CPU通过寄存器EIP指向内存从而获取内存中的数据。EIP总是指向内存的某一块区域(代码段),不断的指向下一条指令,每条指令的长度可能是不同的。我们可以用一个简单的图来描述下:




一、实验内容:通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的

main.c

int g(int x){    return x+4;}int f(int y){    return g(y);}int main(void){    return f(2)+4;}
保存后执行以下命令:

gcc -S -o main.s main.c -m32
其中gcc后面参数含义可以自行man以下,-S表示预处理后可直接对main.c文件编译生产汇编代码,如下所示:
shiyanlou:~/ $ cat main.s                                            [21:59:59].file"main.c".text.globlg.typeg, @functiong:.LFB0:.cfi_startprocpushl%ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl%esp, %ebp.cfi_def_cfa_register 5movl8(%ebp), %eaxaddl$4, %eaxpopl%ebp.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endproc.LFE0:.sizeg, .-g.globlf.typef, @functionf:.LFB1:.cfi_startprocpushl%ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl%esp, %ebp.cfi_def_cfa_register 5subl$4, %espmovl8(%ebp), %eaxmovl%eax, (%esp)callgleave.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endproc.LFE1:.sizef, .-f.globlmain.typemain, @functionmain:.LFB2:.cfi_startprocpushl%ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl%esp, %ebp.cfi_def_cfa_register 5subl$4, %espmovl$2, (%esp)callfaddl$4, %eaxleave.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endproc.LFE2:.sizemain, .-main.ident"GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2".section.note.GNU-stack,"",@progbits
二、实验结果分析:

以上汇编代码中,以点(.)开头的都是用于链接的辅助信息,这些信息是不会被执行的。因此以下分析下除去辅助信息之外的汇编指令:

g:pushl%ebpmovl%esp, %ebpmovl8(%ebp), %eaxaddl$4, %eaxpopl%ebpretf:pushl%ebpmovl%esp, %ebpsubl$4, %espmovl8(%ebp), %eaxmovl%eax, (%esp)callgleaveretmain:pushl%ebpmovl%esp, %ebpsubl$4, %espmovl$2, (%esp)callfaddl$4, %eaxleaveret


程序从main函数开始,假设一开始是一个空栈,如下图所示(在32位环境中,int型数据占4个zi)


pushl%ebp



movl%esp, %ebp


subl$4, %esp

movl$2, (%esp)


callf
call f 的操作其实就相当于pushl %eip;  movl * f, %eip; 从这步开始进入到f函数中的操作


pushl%ebp


movl%esp, %ebp


subl$4, %esp

movl8(%ebp), %eax
以上操作相当于 eax = *(int32_t *) (ebx+4),因此eax = 2

movl%eax, (%esp)


callg

pushl%ebp


movl%esp, %ebp

·

movl8(%ebp), %eax


addl$4, %eax

popl%ebp


ret
ret的操作就相当于pop eip(*),所以esp指针向上移一格,然后代码回到第15行的那条指令



leave
leave指令相当于movl %ebp,%esp; popl %ebp;

ret
回到第23行指令继续执行


addl$4, %eax


leaveret


执行完以上所有代码,我们可以看到堆栈又回到了最初的状态。

三、总结

通过以上逐条指令的分析来理解C语言函数的执行过程,能够加深我们对计算机C语言等高级语言的理解,同时对以后学习用户空间虚拟地址空间打下了基础。

四、实验截图




原创粉丝点击