码迷,mamicode.com
首页 > 其他好文 > 详细

从一段代码的汇编看计算机的工作原理

时间:2015-03-05 12:21:48      阅读:136      评论:0      收藏:0      [点我收藏+]

标签:

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

      大家都知道,现在的计算机主要遵循的是所谓的“冯诺依曼框架”。那什么是冯诺依曼框架呢,其实就是计算机通过总线从内存中读取一条条的程序和数据,将它们存储在自己的寄存器中一条条地执行,如下图所示。

  技术分享

  而今天,我们将通过汇编一个具体的C程序来探讨计算机工作的流程。

     首先写下这么一段C程序:

 1 //linux.c
 2 int g(x)
 3 {
 4     return x+3;
 5 }
 6 int f(x)
 7 {
 8     return g(x);
 9 }
10 int main()
11 {
12     return f(10)+1;
13 }

  在Linux的环境中输入如下指令:

gcc –S –o linux.s linux.c -m32

  然后打开linux.s,就可以看到我们汇编后的代码(直接上截图了)

 技术分享

   将里面以“.”开头的行去掉(这是为链接用的),得到汇编后的代码:

 1 g:
 2     pushl   %ebp
 3     movl    %esp, %ebp
 4     movl    8(%ebp), %eax
 5     addl    $3, %eax
 6     popl    %ebp
 7     ret
 8 f:
 9     pushl   %ebp
10     movl    %esp, %ebp
11     subl    $4, %esp
12     movl    8(%ebp), %eax
13     movl    %eax, (%esp)
14     call    g
15     leave
16     ret
17 main:
18     pushl   %ebp
19     movl    %esp, %ebp
20     subl    $4, %esp
21     movl    $10, (%esp)
22     call    f
23     addl    $1, %eax
24     leave
25     ret

   接下来我们来分析一下改程序具体的流程。

  程序一开始,CPU的IP寄存器指向汇编代码的第18行,假设堆栈在内存中的地址分别为0,1,2,3……堆栈基指针寄存器(EBP)和堆栈顶指针寄存器(ESP)均指向堆栈段0处。

  第18~21行首先为main函数开辟新的内存区域,之后将传的参数10入栈,此时堆栈段如下所示:

  技术分享

  然后程序调用call 函数,将IP入栈,IP指向代码第9行f处。

  在f函数的代码处,首先为f函数开辟新的内存区域,接着将传入的参数10赋值给EAX,并将EAX入栈,此时堆栈段内存如下图:

技术分享

  程序在此调用call进入g函数。在g函数中,同样先是开辟内存空间,然后将参数传给EAX,并将EAX的值加上3。

  之后将EBP出栈,并调用ret命令。此时IP重新指向f函数call之后的命令,堆栈内存的情况如下:

  技术分享

  之后就是不断的调用leave与ret命令,跳出当前的内存区域,回到上一级函数的内存区域中,并将EAX的值加3,直到跳出main函数,至此程序结束。

  从上面的分析中,我觉得可以归纳出以下几点:

  1.计算机的运行流程确是遵循冯诺依曼框架,CPU将内存中的代码和数据读取到自己的寄存器中,再根据一条条命令调用寄存器进行进一步的操作。

  2.在进入每一个程序之前,CPU都会将上一级的EIP和EBP压栈,相当于为新的函数重新开辟了一段新的内存空间,直到退出函数的时候才将它们出栈。

  3.CPU的各个寄存器都有不同的分工,如EIP指向要执行的代码,EAX存储返回值等。它们贯穿于整个程序执行流程,自己写程序时一般不要轻易改动。

  

从一段代码的汇编看计算机的工作原理

标签:

原文地址:http://www.cnblogs.com/wickedpriest/p/4315189.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!