Linux内核分析(一):计算机工作原理

来源:互联网 发布:select to SQL 编辑:程序博客网 时间:2024/05/17 03:46

何天杨+ 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
一、计算机是如何工作的
现代计算机大都采用冯诺依曼结构,冯诺依曼结构是一种将程序指令存储器和数据存储器合并在一起的存储器结构。程序指令存储地址和数据存储地址指向同一个存储器的不同物理位置,所以计算机在运行的时候需要从中将数据取出,然后用程序进行处理,最后得到输出。我们以汇编一段简单的C语言程序作为例子讨论计算机如何工作:

  int g(int x)  {    return x + 22;  }  int f(int x)  {    return g(x);  }  int main(void)  {    return f(10) + 1;  }    

汇编代码
从main函数开始:

 main:  pushl   %ebp          ;帧指针入栈,便于以后恢复(此帧指针为调用main函数的帧指针)  movl    %esp, %ebp    ;设置当前的帧指针(始终指向栈底,便于对参数之类的进行寻址及以后的恢复)  subl    $4, %esp      ;分配空间,用于传递参数给int f(int x)  movl    $10, (%esp)   ;给分配的空间赋值  call    f             ;调用函数f  addl    $8, %eax      ;设置返回值(当返回参数较小时,能够用32位eax保存的,否则可能用eax表示指针,指向返回值)  leave                 ;相当于 movl %ebp, %esp   popl %ebp  ret                   ;返回函数调用的下一句  

下面是g函数:

g:      pushl   %ebp      movl    %esp, %ebp      movl    8(%ebp), %eax  ;将[ebp+8]地址里的数据传入eax中,                            即取出输入参数     addl    $22, %eax      popl    %ebp      ret  

f函数:

f:      pushl   %ebp      movl    %esp, %ebp      subl    $4, %esp      movl    8(%ebp), %eax      movl    %eax, (%esp)      call    g      leave      ret 

二,堆栈分析:

pushl   %ebp  movl    %esp, %ebp

上面两行实际上是对内存堆栈的一个操作,程序执行是需要内存的,所以每次有新的函数过程被调用的时候计算机也必须分配一段内存。%ebp+%esp所在的地址就是相对应的内存,%esp叫做叫做堆栈指针,而每一个函数都有自己的内存空间也就是堆栈。不同的函数堆栈是由%ebp标注的,即堆栈的基地址,就是一个堆栈开始的地方。所以每个代码段或者说函数段在运行的时候都会保存上一个运行的函数的基地址,用于它运行完之后返回到调用它的那个代码段的地方。然后在将自己的堆栈指针所指向的地址放入到基址寄存器中,相当于开辟出一个新的堆栈,之后就可以开始自己的代码运行。
main函数中首先保存了当前的堆栈基地址(ebp-0入栈了esp-0向下移动了一个单位-4到达esp-1),然后将ebp-0移动到esp-1的位置成为ebp-1然后esp-1再向下移动一个单位到达esp-2,保留这个位置用于保存其调用函数的返回值,这个值在那个函数中用eax来传递后面会讲到。然后将调用f函数时候需要传入的参数10放入堆栈中esp-2指向的位置。然后调用f函数,这个时候需要先保存一下当先的ebp,也就是epb-1。
然后来到了f函数中,首先也是将ebp-1入栈然后将ebp指向当前esp-4的位置(每次伴随入栈操作都会影响esp的值)到达ebp-2,然后esp在向下移动一个单位到达esp-5。留出一个返回值的位置然后将当前ebp+8中的值传入eax用于返回。然后将eax中的值传入esp,然后重复上述过程调用g函数。g函数返回32,然后到f中,f也返回32。然后回到main中执行addl 8,fg使subl4, %esp,使得堆栈指针向下移动一个单位。然后调用movl8(%ebp), %eax找到第一个传递进去的参数。(就是10—>f(10))

三、总结
上述分析过程大致说明了函数之间调用的过程。基本上每个被调用的函数使用的内存空间都大体上先包括这么几个部分:
1.函数的运行所用参数(C语言中的函数参数列表)
2.函数的运行过程中产生的数据(运行的中间结果和返回值)
3.调用它的函数的入口地址
4.保存它调用的函数的返回值的空间
所以对应的调用别人函数就要传入入口参数,就是比如f(10)中的10就是这样的入口参数
程序通过函数的顺序调用实现,及保护现场和恢复现场机制,ebp基址寄存器保存当前函数的基栈地址,call、ret调用函数及返回时由eip来保存下一条指令地址和基栈地址,并利用寄存器来保护现场,函数的返回值默认使用eax寄存器存储返回给上一级函数,恢复现场后继续执行程序直至程序结束。
由上述简单的汇编程序可以看出,计算机工作的核心,即取指,执行。冯·诺依曼体系结构的计算机主要思想即存储程序计算机。计算机工作过程就是不断的取指令,执行指令,并将结果存储在指令指定的存储器中。计算机执行程序时先将要执行的相关的程序及数据存入内存中,CPU根据当前IP取出指令并执行指令,循环往复至程序结束,指令停止执行。

四、实验截图
进入终端
汇编C程序
生成的带有注释码的汇编文件
去掉注释的汇编代码
这里写图片描述

0 0
原创粉丝点击