Linux内核分析作业(1)——计算机是如何工作得?

根据163MOOC学院中国科学技术大学孟宁孟老师课程所写得博客

作者:肖冲冲 原创作品请注明出处

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

一,计算机的工作过程

   计算机的基本原理是存储程序和程序控制(冯﹒诺依曼体系),简单来说,我们需要先把需要进行操作的指令(程序)和数据先输入到计算机的存储设备中,然后计算机将严格执行需要执行的指令,包括从那个地址取数(或指令),进行什么操作(加减移位等),然后再送回到什么地址。

   从硬件上来说,组成现代CPU的基础元件的有超大规模的逻辑门,定时器,以及高性能的cache和高精度时钟。逻辑门提供逻辑仲裁功能,运算器精于各种运算,cache提高数据交换效率。

   从软件上来说,我认为我们的程序就是与计算机尤其是CPU上面的各种寄存器进行数据交互来使用计算机的硬件功能,比如网络通信,就是我们的程序使用网络接口进行数据交互。或者最经典的C语言打印“hello world”这个程序,简单说来就是我们的程序控制CPU相关的寄存器在显存里面写入了“hello world”这个字符串显示的相关指令和数据。在这个过程中,软件控制硬件目的就是,我们的显示器上面显示出了“hello world”,而这一过程本身可以抽象为软件和显示设备之间的数据交互。

   总得来说,在计算机上,软件承担着主动向硬件进行数据交互的任务,而硬件是被动的接收和响应处理这些数据(当然你得按照正确的时序来操作还得保证输入正确的数据)。那么有没有硬件是可以主动去做一些事情呢,当然是有得,在ASIC里面,都是先通过软件(现在大部分是FGPA级实现)来进行模拟验证,然后再通过纯硬件实现相关功能。

   而我们计算机的工作过程,我认为就是软件操作这些硬件的过程。

   至于如何来操作这些东西,我们需要了解CPU的寄存器,基础的汇编指令等。

   下面我跟着孟老师的课程,反汇编一段C语言代码来简单介绍下这个过程和涉及的相关知识。

二,汇编代码工作过程中堆栈过程的变化

    至于如何到实验楼进行相关实验,在孟老师的视频讲得非常详细,这里略过不表。

我的过程截图如下:

技术分享

实验楼里面的虚拟机,使用非常方便。

技术分享

这个是我们的目标c代码,很简单的一段代码。

编译命令如下:

技术分享
1 int g(int x){
2     return x + 3;
3 }
4 int f(int x){
5     return g(x);
6 }
7 int main(void){
8     return f(8) + 1;
9 }
简单的C语言代码

 

技术分享

使用如下命令产生汇编代码:

gcc -S -o main.s main.c -m32

注意:此处-m32参数是反编译成32位的汇编指令,因为实验楼所提供的虚拟机是64位的,所以加上该参数。我实验了下,如果不加入该参数,所得到的指令会掺杂64位的指令。比如movq和pushq等。

所生成的汇编代码如下(该代码已经将一些标志符等进行了删减以利于分析):

技术分享
 1 .file    "main.c"
 2 g:
 3     pushl    %ebp
 4     movl    %esp, %ebp
 5     movl    8(%ebp), %eax
 6     addl    $3, %eax
 7     popl    %ebp
 8     ret
 9 f:
10     pushl    %ebp
11     movl    %esp, %ebp
12     subl    $4, %esp
13     movl    8(%ebp), %eax
14     movl    %eax, (%esp)
15     call    g
16     leave
17     ret
18 main:
19     pushl    %ebp
20     movl    %esp, %ebp
21     subl    $4, %esp
22     movl    $8, (%esp)
23     call    f
24     addl    $1, %eax
25     leave
26     ret
反编译出来的汇编代码

 下面进入正题。

首先来说下几个基础点:

1,几个寄存器的名称和作用

  • EIP   32位指令寄存器 用于存放下一次需要执行的指令地址,在当前的指令地址被取出之后,会自动的+1
  • EBP  扩展基址指针寄存器其内存放一个指针,该指针指向系统栈最上面一个栈帧的底部
  • ESP  栈指针,用于指向栈的栈顶(下一个压入栈的活动记录的顶部),而EBP为帧指针,指向当前活动记录的底部
  • EAX 是一种32位通用寄存器。 EAX寄存器称为累加器,AX寄存器是算术运算的主要寄存器,所有的输入、输出只使用AL或AX人作为数据寄存器

2,函数调用的堆栈是由多个堆栈叠加起来得。我的理解如下图示,函数example()占用了如下的一段空间,而它是由函数内的多个栈叠加起来得(由于当初堆栈学得不太好,此处不知道理解得是否正确?):

  技术分享

3,函数的返回值默认由EAX寄存器存储返回给上一级的函数。

4,pushl %ebp,将当前ebp压栈同时esp的值被修改。

5,在程序中,

  • ret    =  popl %eip
  • enter = push %ebp

                movl %esp,%ebp

  • leae  =  movl %ebp,%esp

                popl %ebp

下面看具体分析:

技术分享
 1 .file    "main.c"
 2 g:                            ;函数g
 3     pushl    %ebp             ;将ebp压栈,同时esp的值减去4个字节,栈向下增长一段
 4     movl    %esp, %ebp        ;采用寄存器寻址的方式,将esp的值赋给ebp
 5     movl    8(%ebp), %eax     ;将ebp变址寻址加8,将该地址的栈空间存储的值赋给eax
 6     addl    $3, %eax          ;将eax里面存储的数据加3,即实现 8 + 3的操作,然后将结果赋值给eax,此时eax=11
 7     popl    %ebp              ;将ebp出栈,此时esp加上4个字节,指向了原先存储着leavel的栈位置
 8     ret                       ;将eip出栈,回退到上一个跳转时的位置下一段指令,即f函数中的leave处
 9     
10 f:                            ;函数f
11     pushl    %ebp             ;将ebp压栈,同时esp的值减去4个字节,栈向下增长一段
12     movl    %esp, %ebp        ;采用寄存器寻址的方式,将esp的值赋给ebp
13     subl    $4, %esp          ;将esp的值减4个字节,即栈向下再增长一段
14     movl    8(%ebp), %eax     ;将ebp变址寻址加8,将该地址的栈空间存储的值赋给eax
15     movl    %eax, (%esp)      ;将eax的值赋给esp所指向的地址的栈空间
16     call    g                 ;跳转到函数g,执行之后EIP指向leave的值将会保存到栈中
17     leave                     ;leave指令此时将ebp的值赋值给esp,然后将ebp出栈,然后esp将指向存储着上一个函数跳转时的下一段指令,即函数main中的addl处      
18     ret                       ;将eip出栈,回退到上一个跳转时的位置下一段指令,即main函数中的addl处
19     
20 main:                         ;程序的入口点
21     pushl    %ebp             ;将ebp压栈,同时esp的值减去4个字节,栈开始向下增长
22     movl    %esp, %ebp        ;采用寄存器寻址的方式,将esp的值赋给ebp
23     subl    $4, %esp          ;将esp的值减4个字节,即栈向下增长一段
24     movl    $8, (%esp)        ;对esp所指向的栈空间赋值为8
25     call    f                 ;跳转入函数f,转向f段代码,此时EIP指向函数f
26     addl    $1, %eax          ;将eax中的值加1并存入eax,此时eax = 12
27     leave                     ;此时将ebp的值赋值给esp,然后esp将指向栈尾0,然后将ebp出栈,同样ebp也将指向栈尾0
28     ret                       ;将eip出栈,因为没有下一条指令,程序至此执行完毕。
汇编代码中堆栈的变化 
时间不多了,后续补充一个流程图来详细描述该堆栈过程。
该篇文章里面也许会有很多错误的地方,尤其最后汇编程序堆栈分析,我应该还没能完全理解孟老师的意思,恳请各位指正,互相交流学习。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。