“Linux内核分析”实验一

通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的

 

作者:何振豪

原创作品转载请注明出处 http://www.cnblogs.com/scoyer/p/6411414.html

《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000

 

计算机由硬件和软件组成,硬件主要是CPU和内存,软件是分成系统软件和应用软件。最开始的计算机是由冯诺依曼提出的存储程序的思路开始的,这就对应硬件的CPU和内存,CPU执行指令,指令和相关数据放在内存,CPU按照ecs::eip指示的地方取出指令执行,不断执行。操作系统是系统软件,主要的作用是为应用软件提供接口,程序猿根据这些接口进行编程,形形色色的应用软件就这样产生了。Linux是一个非常优秀的操作系统,系统的代码是开源的,所以研究linux内核是了解计算机怎么工作的一个重要途径。Linux要面对的是怎么规划计算机硬件使得他们能够互相协作,一步一步执行相应的代码。

 

当前这个实验要求的是反汇编一个简单的c程序,直接阅读汇编代码对理解计算机硬件的核心工作机制(存储程序计算机和函数调用堆栈)有一定的帮助。下面我将一段简单的c代码进行编译成汇编文件,然后分析每个具体的执行过程,最后在总结一下汇编执行c代码的一些特点。

 

实验环境:实验楼

 

1.建立一个c文件exp.c

exp.c代码如下:

 

2.输入下面的指令编译成汇编代码:

  1. gcc –S –o exp.s exp.c -m32

 

3.开始得到的代码很多系统参数代码,删掉所有开头带.的代码,得到如下代码:

 

 

对上述汇编代码进行简单分析如下,假设一开始的堆栈状态如下:

 

 

0

 

1

 

2

 

3

 

4

 

5

 

6

 

7

 

8

 

9

 

假设一开始的esp = ebp = -1,为什么等于-1呢?首先由pushl的命令可知,esp指向的栈顶是最后放数据的地方,我们这上面栈是从0开始,也就是0这个位置是第一个放数据的地方,所以第一次执行pushl之后,0这个位置就有东西,并且esp指向最后放数据的地方,也就是0.

我们都知道c语言的执行函数是main,所以从第19行开始执行,逐行解释如下:

(1)将ebp入栈,这时候的esp-4即变成图中标号为0的位置esp=0,然后把ebp推入栈即[0] = ebp -1;

(2)ebp = esp = 0

(3)esp=1

(4)[1] = 10

(5)跳转到f函数去执行,这时候执行的call指令包含两条,一是将当前的eip保存到栈中,所以esp=2,[2] = eip 24(表示当前执行指令的行号的下一条);二是将eip设置为f函数的第一条指令,所以eip被修改为第九行的地址,所以下面执行的指令是第九行开始

(6)esp = 3,[3] = ebp 0

(7)esp = ebp = 3

(8)esp = 4

(9)eax = (ebp - 2(两个字节)) = [1] = 10(传给f函数的值)

(10)eax = 10 + 11 = 21

(11)[4] = 21

(12)跳转到g函数去执行,执行call指令按照上面叙述的两步进行得到:esp = 5, [5] = eip 16, eip = 2,所以下面的指令从第二行开始

(13)esp = 6, [6] = ebp 3

(14)esp = ebp = 6

(15)eax = (ebp - 2(两个字节)) = [4] = 21

(16)eax = 12 + 21 = 33

(17)ebp = [6] = 3, esp = 5

(18)ret命令即pop %eip,所以现在是eip = [5] = 16, esp = 4调回到第16行开始执行

(19)leave也是包含两条指令,esp = ebp = 3,ebp = [3] = 0,esp = 2

(20)eip = [2] = 24, esp = 1调回到24行开始执行

(21)eax = 34

(22)esp = ebp = 0,ebp = [0] = -1, esp = -1

(23)最后这个ret是恢复到最开始的栈现场

 

现在我们总结一下在汇编中执行c代码的特点:

(1)当执行f函数的时候做了什么准备工作:

①进入函数f之前,call指令把当前的eip保存到栈中,修改eip指向当前的函数

②执行enter指令,保存之前的栈底指针,清空当前的栈,然后再往下执行函数代码,执行完之后利用leave恢复调用函数前的栈指针

③把要传给f函数的参数放到栈中

(2)函数要返回的参数保存在eax这个寄存器 

 

总的来说,CPU不断执行eip指向的地方的代码,利用堆栈(当然不只是堆栈)来存储相应的数据和保存调用现场,计算机就是通过CPU和内存互相协助不断执行相应指令,利用存储程序的特点一步一步工作的。当然,CPU和内存只是硬件支持,真正使得这些程序能够有条不紊并且发挥CPU等硬件的最大作用的还是操作系统。操作系统为硬件和软件架起了一条交流的康庄大道。

posted @ 2017-02-17 20:19  scoyer  阅读(571)  评论(0编辑  收藏  举报