计算机是如何执行程序的(以汇编一个简单的C程序,分析汇编代码为例)

时间:2022-05-02 11:46:06

作者:ahnselina 

原创作品转载请注明出处

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

本文尝试以一个简单的C程序及其汇编代码为例,分析计算机是如何执行程序的。

首先来看下计算机的基本模式:

计算机是如何执行程序的(以汇编一个简单的C程序,分析汇编代码为例)

如图,计算机基本都是这种CPU通过总线与内存相连的模式,

CPU上有各种寄存器,如下

计算机是如何执行程序的(以汇编一个简单的C程序,分析汇编代码为例)

其中比较重要的寄存器有EIP寄存器(IP:Instruction Pointer,在32位系统中,该寄存器叫EIP,64位系统中叫RIP),可以把该寄存器看做指针,它指向CPU将要执行的下一条指令。

计算机是如何执行程序的(以汇编一个简单的C程序,分析汇编代码为例)

从程序员的角度可以把计算机执行程序的过程简单理解为如下:

计算机是如何执行程序的(以汇编一个简单的C程序,分析汇编代码为例)

即:CPU在内存中取一条指令,执行,执行完后再取下一条指令,如此往复循环,其中EIP就指向内存区域CS段(代码段)。


下面通过实际例子来分析计算机执行汇编程序的过程

下面为test.c的代码:

int g(int x)
{
return x + 1;
}


int f(int x)
{
return g(x);
}


int main(void)
{
return f(6) + 3;
}

使用如下命令:gcc -S -o test.s test.c -m32

计算机是如何执行程序的(以汇编一个简单的C程序,分析汇编代码为例)

编译出汇编文件(编译出来的原始文件有些其他信息,已经被删除,剩下的干净的汇编代码如下图):

计算机是如何执行程序的(以汇编一个简单的C程序,分析汇编代码为例)

下面我们来从main函数开始分析汇编代码:

主要分析过程如图,我们做一些约定:系统默认为32位的

a.假设开始的时候堆栈的基指针%ebp和%esp都指向栈底(地址10)的地方,也就是说这时栈为空;

b.图中10-9-8-7....表示地址,也表示堆栈由高地址向低地址生长,同时每个地址之间相差4。

也就是初始状态如图①所示,

1.第19行开始执行,

pushl %epb
这个入栈操作,对应有两个操作

subl $4, %esp
movl %ebp, (%esp)
即通过19行的入栈,堆栈状态由图①变到图2;

2.执行

movl %esp, %ebp
堆栈状态由图2变到图3;

其实这1和2两步对应了enter命令:

pushl %ebp
movl %esp,%ebp

3.执行

subl $4, %esp
堆栈状态由图3变到图4,即%esp栈顶指针向下移4,到位置8的地方(图4的那个位置标记写错了);

4.执行

movl $6, (%esp)
堆栈状态由图4变到图5,同时将6这个立即数存到目前%esp所指的地方;

5.执行

call f
这个对应操作为:
pushl %eip(*)movl f, %eip(*)
此时eip指向f函数

堆栈状态由图5变到图6;

执行完call f后,跳转到执行f函数

6.此时又是执行

pushl %ebp
堆栈状态由图6变到图7;

7.执行

movel %esp, %ebp
堆栈状态由图7变到图8;

计算机是如何执行程序的(以汇编一个简单的C程序,分析汇编代码为例)

8.执行

subl $4, %esp
堆栈状态由图8变到图9;

9.执行

movl 8(%ebp), %eax
即把(%ebp-8)--->%eax,也就是把图10中位置8里面的数值存到寄存器eax中。

10.执行

movel %eax, (%esp)
堆栈状态由图9变到图10,即把6放入位置5;

11.执行call g

类似call f

堆栈状态由图10变到图11;

跳转到执行g函数

12. 执行

pushl %ebp
堆栈状态由图11变到图12;

13.执行

movl %esp, %ebp
堆栈状态由图12变到图13;

计算机是如何执行程序的(以汇编一个简单的C程序,分析汇编代码为例)

14.执行

<span style="font-size:18px;">movl 8(%ebp), %eax
addl $1, %eax</span>
6+1 --->eax

15.执行

popl %ebp
堆栈状态由图13变到图14;
16.执行ret

堆栈状态由图14变到图15;

解释:ret实际是

popl %eip(*)

eip指向第16行

17.执行leave

leave实际对应指令

movl %ebp,%esp
popl %ebp
所以堆栈状态由图15变到图16图17;

18.ret

同16

堆栈状态由图17变到图18;

eip指向第24行

19.执行

addl $3, %eax
此时eax寄存器中值为6+1+3;

20.执行leave

同上

堆栈状态由图18变到图19图20;

可以看到这时的堆栈状态已经恢复到最开始的状态了。

计算机是如何执行程序的(以汇编一个简单的C程序,分析汇编代码为例)

总结:计算机执行程序,需要先将程序转化成自身可以执行的命令,然后再一条一条的执行这些命令。

注意计算机是不能直接执行汇编程序的,计算机只能识别机器语言,不过通过例子可以看到汇编可以直接操作CPU的某些寄存器,因此效率比其他语言高,不过编写代码的效率就不如其他语言了。

主要参考此门课程课件:《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000