2019-2020-1 20199308《Linux内核原理与分析》第二周作业

《Linux内核分析》

第一章 计算机工作原理

1.1 存储程序计算机工作模型

  • 冯·诺依曼体系结构
    各种计算机体系结构需要遵从的一个“客观规律”
    • 结构图

    • 冯·诺依曼体系结构的核心是存储程序计算机。
    • 内存保存指令和数据,CPU负责解释和执行这些指令,它们通过总线连接起来。
      存储程序计算机工作原理示意图

    • 对于x86-32计算机,有一个EIP寄存器指向内存的某一条指令,EIP是自动加一的(加一条指令)。

1.2 x86-32 汇编基础

1.2.1 x86-32 CPU的寄存器

  • 开头为E的寄存器,一般是32位的。
  • 32位寄存器EAX、EBX、ECX和EDX不仅可以传送数据、暂存数据保存算数逻辑运算结果,还可以作为指针寄存器。
  • 段寄存器
  • 代码段:使用CS:EIP来准确指明一个指令的内存地址(即首先需要知道代码在哪一个代码段里,然后需要知道指令在代码段内的相对偏移地址EIP)。

  • 堆栈段:每一个进程都有自己的堆栈段。
  • 开头带R的都是指64位寄存器。

    1.2.3 寻址方式和常用汇编指令

  • 最常见的汇编指令是mov指令,movb是指8位;movw是指16位;movl是指32位;movq是指64位。
  • 寻址方式
  • x86-32中的大多数指令都能直接访问内存,但还有一些指令能直接对内存操作,如mov,push/pop等。
  • 压栈:pushl表示32的push:
pushl %eax

就是把EAX寄存器的值压到堆栈栈顶。实际上是两个动作:
①把堆栈的栈顶ESP寄存器的值减4。(因为堆栈是向下增长的,所以用减指令subl,也就是在栈顶预留出一个存储单元

subl $4, %esp

②间接寻址,就是把EAX寄存器的值放到ESP寄存器所指向的地方,这时ESP寄存器已经指向预留出的存储单元。

movl %eax, (%esp)
  • 出栈:
popl %eax

从堆栈的栈顶取一个存储单元,从堆栈栈顶的位置放到EAX寄存器里。实际上也是两个动作:
①把栈顶的数值放到EAX寄存器里。

movl (%esp), %eax

②用指令addl把栈顶加4,相当于栈向上回退了一个存储单元的位置,也就是栈在收缩。

addl $4, %esp

每次执行指令pushl栈都增长,执行指令popl栈都收缩

  • call指令是函数调用,相当于两个动作:
push %eip
movl f %eip
  • ret指令是函数返回
  • EIP寄存器不能被程序员直接修改,只能通过专用指令(如call、ret和jmp等)间接修改。

1.2.4 汇编代码范例解析

以下两个片段变化的效果是一样的

以下片段稍有复杂(书P12)

1.3 汇编一个简单的C语言程序并分析其汇编指令执行过程

  • “ls”命令查看目录

vi main.c命令打开VIM编辑main.c文件

gcc main.c命令直接编译
echo $?命令查看这个程序的返回值

gcc -S -o main.s main.c -m32命令把main.c编译成一个汇编代码
在VIM编辑器中用
g/\.s*/d命令删除所有辅助信息,获得“干净”的汇编代码

  • 分析上述“干净”的汇编代码
1 g:
2   pushl   %ebp  //将EBP压栈,将位置4存到位置7;ESP也指向位置7。
3   movl    %esp, %ebp  //将EBP也指向位置7。
4   movl    8(%ebp), %eax  //EBP变址寻址,加8,即指向位置7不动,并把位置5的内容(即立即数8)放入EAX(取出函数g的参数)。
5   addl    $3, %eax  //将立即数3加到EAX中,即8+3,EAX为11。
6   popl    %ebp  //将位置7的内容(即位置4)放回EBP(即恢复函数f的函数调用堆栈基址EBP),即EBP指向位置4;【同时ESP加4,指向位置6】。
7   ret  //(popl%eip)将ESP所指向的内容,即行号15放入EIP,即EIP指向行号15;同时ESP加4,即指向位置5。
8 f:
9   pushl   %ebp  //将EBP向下移动(从EIP的位置3开始),指向位置4。
10  movl    %esp, %ebp  //将ESP也指向EBP的位置4。
11  subl    $4, %esp  //ESP减4,指向位置5。
12  movl    8(%ebp), %eax  //EBP变址寻址8,向上移动两个存储单元即加两个标号的位置,即指向位置2;并将位置2存储的立即数8放到EAX中。
13  movl    %eax, (%esp)  //将EAX放入ESP中,即立即数8放入位置5。
14  call    g  //类似第22行,将ESP指向位置6,;把EIP行号15放到位置6,并指向函数g的位置即第2行。
15  leave  //撤销函数堆栈,等价于=(movl %ebp,%esp和popl %ebp),即将EBP的内容(位置4)放入ESP,即ESP也指向位置4;【然后把位置4的内容(即位置1)放回EBP,即EBP指向位置1;同时ESP加4,指向位置3。】
16  ret     //将ESP所指向的位置3的内容(即行号23)放到EIP中,即EIP指向行号23,;同时ESP加4,指向位置2。 
17 main:
18  pushl   %ebp  //开始执行第一条指令,EIP自动加1即指向行号19;把EBP的值压栈,先将EBP指向位置1,再将EBP的值标号0。
19  movl    %esp, %ebp  //EIP自动加1即指向行号20;将EBP指向位置1。
20  subl    $4, %esp  //EIP自动加1即指向指向行号21;将ESP减4,即向下移动,指向位置2。
21  movl    $8, (%esp)  //EIP自动加1即指向行号22;把立即数8放入ESP,仍指向位置2(20和21行同作为压栈f函数所需参数)。
22  call    f  //执行此行时,EIP已经自动加1指向了下一行即指向行号23(pushl %eip),然后将函数f的开始指令放入EIP(movl f %eip),即EIP指向函数f的位置即第9行。
23  addl    $1, %eax  //将EAX加立即数1,即11+1,EAX的值为12,(EAX是默认存储函数返回值的寄存器)。
24  leave  //撤销函数main堆栈,将EBP和ESP都指回位置1,【同时把位置1存储的内容(即位置0)放到EBP,即EBP指向位置0;并ESP加4,也指向位置0】。
25  ret  //指令结束。

【】中内容没太整明白

  • leave指令等价于令:
movl %ebp,%esp
popl %ebp
  • enter指令等价于:
pushl %ebp
movl %esp, %ebp

猜你喜欢

转载自www.cnblogs.com/hsj910/p/11563286.html