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

作者:ahnselina 

原创作品转载请注明出处

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

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

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


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

CPU上有各种寄存器,如下


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

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


即: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


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


下面我们来从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;


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;

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;

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


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

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

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

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值