[网易云课堂]Linux内核分析(一)——简单C程序汇编代码分析

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

本实验代码库;

本文将通过一个简单的C语言程序(包含两层简单传值函数调用)分析其对应的汇编代码,从而初窥计算机在汇编指令层面上的执行过程。本文不涉及到编译器翻译C至汇编代码的过程,运行环境为64位linux系统;

一、von Neumann 结构

现代大多数计算机由运算器、存储器、控制器、输入设备、输出设备五大部件组成。

  • von Neumann结构应该是所有学习计算机的人都必定会接触到的结构,绝大多数现代计算机系统是建立在von Neumann体系结构上的。
  • von Neumann结构的中心思想在于存储程序。即将中央处理器与存储区分离,所有程序存储在存储器中。处理器根据寄存器值,依次取出指令并顺序执行。
  • 如有不清楚的,可参阅维基百科 - 冯·诺伊曼结构

二、课程实验分析

汇编一段简单的C语言代码,观察代码执行过程。未提及的概念若在分析过程中遇到将在分析过程中简略提及,详情请参见课程主页

  • 运行实验楼环境,创建main.c。如下为main.c

main.c截图

可以看到main函数使用参数12,调用函数f,f调用函数g,g返回12+10给f,f返回22给main,main再加1993后返回。

  • 使用 gcc -S -o main.s main.c -m32 将上述C语言文件编译为汇编代码main.s,如下所示。(注:该命令仅适用于64位linux系统,32位linux系统可能稍有不同)(注:截图不完整,请点击链接查看完整源代码)

main.s截图

其中以.开头的是一些标签,帮助程序将来能够更好的进行链接,在这里不对它进行讨论。将所有带.的标签删除后,得到withoutdotmain.s,如下所示:

withoutdotmain.s截图

  • 运行过程分析:
    1、程序从main入口进入,运行
    pushl %ebp
    movl %esp, %ebp
l的意思为其后进行的操作为32位的操作。pushl的作用是使栈基指针%ebp压栈,即让栈顶指针%esp所指位置的值(注:所指位置的值与%esp本身的值不同,前者为(%esp)后者为%esp)变为栈基指针%ebp的值,并将栈顶指针%esp减去一个栈元素的单位(在32位中为4个bytes)(注:栈是向下增长的)。
而后movl %esp, %ebp将当前%esp的值赋给%ebp。每一个函数进入时都将进行这两步,下不赘述。

2、程序将esp减4subl $4, %esp即下移一个单位。并使当前栈顶指针所指的值变为12movl $12, (%esp), 而后使用call f调用函数f 。这条指令同时也会将%eip压栈并将f的入口地址赋予%eip(%eip保存的是函数在不跳转或不调用情况下下一条应该执行的程序地址),故%esp会下移一个单位。此时12的位置在4(%esp)。
图1

3、进入函数f,栈基指针入栈和栈顶指针下移更改。此时12的位置在%8(ebp)(又执行了一次入栈,%8(esp)也指向相同位置,因为两个指针现在指向同一个位置)将8(%ebp)值赋给通用寄存器%eax,即将12赋予%eaxmovl 8(%ebp), %eax,相当于函数传递形参。而后用%eax的值修改%esp当前所指的位置的值movl %eax, (%esp)。而后使用call g调用函数g,即将%eip压栈,将%esp减4,并将函数g的入口地址赋予%eip。
图2

4、进入函数g,栈基指针入栈和栈顶指针下移更改。此时12的位置与3中f的情况类似,故movl 8(%ebp), %eax即将形参12赋予%eax,而后执行+10的操作addl $10, %eax,使之前压栈的栈基指针出栈popl %ebp(得到上一个函数栈基信息), 而后使用ret指令返回。ret指令与call相反,即将%eip出栈,修改%esp,得到调用函数下一条指令的执行地址。
图3

5、返回函数f,执行leave指令,相当于执行

    movl %ebp, %esp 
    popl %ebp

其作用在于撤销进入函数时创建的堆栈。其后调用ret指令返回main函数。

6、main函数返回至addl $1993, %eax,对%eax执行加法操作,得到最终结果,而后使用leave,ret返回。注意%eax在函数调用过程中值不修改,因此可以用来保存最终的运行结果。
图4

三、心得总结

这一章的内容还算比较简单,部分难点在于一些指令实际执行的内容不清楚,比如call,ret,leave(百度百科上对于leave指令的解释应该是错的)等,导致对程序运行的堆栈有些许疑惑。整体来说还算比较顺利。但博客编写花了比较多的时间,一方面是较少使用markdown,另一方面是在画图和语言组织上花费了一些功夫。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值