2019-2020-1 20199303<Linux内核原理与分析>第二周作业

2019-2020-1 20199303<Linux内核原理与分析>第二周作业

1.汇编与寄存器的学习

寄存器是中央处理器内的组成部份。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和位址。在中央处理器的控制部件中,包含的寄存器有指令寄存器(IR)和程序计数器(PC)。在中央处理器的算术及逻辑部件中,包含的寄存器有累加器(ACC)。

  寄存器是内存阶层中的最顶端,也是系统获得操作资料的最快速途径。寄存器通常都是以他们可以保存的位元数量来估量,寄存器通常都用来意指由一个指令之输出或输入可以直接索引到的暂存器群组。寄存器是CPU内部的元件,寄存器拥有非常高的读写速度,所以在寄存器之间的数据传送非常快。
寄存器用途:

  1.可将寄存器内的数据执行算术及逻辑运算;

  2.存于寄存器内的地址可用来指向内存的某个位置,即寻址;

  3.可以用来读写数据到电脑的周边设备。

操作寄存器的寻址方式有七种
立即寻址方式(Immediate addressing)

寄存器寻址方式(Register addressing)

直接寻址方式(Direct addressing)

寄存器间接寻址方式(Register indirect addressing)

寄存器相对寻址方式(Register relative addressing)

基址变址寻址方式(Based indexed addressing)

相对基址变址寻址方式(Relative based indexed addressing)

2.实验过程

首先熟悉一下vim操作

然后测试的代码

int g(int x)
{
return x+5;
}

int f(int x)
{
return g(x);
}

int main(void){
return f(8)+1;
}  

输入gcc -S -o main.s main.c -m32得到main.s的汇编文件,可以用vi main.s打开得到的汇编代码与实验楼得到的代码有所区别。

1.file   "main.c"
2         .text
3         .globl  g
4         .type   g, @function
    5 g:
    6 .LFB0:
    7         .cfi_startproc
    8         pushl   %ebp
    9         .cfi_def_cfa_offset 8
10         .cfi_offset 5, -8
11         movl    %esp, %ebp
12         .cfi_def_cfa_register 5
13         movl    8(%ebp), %eax
14         addl    $5, %eax
15         popl    %ebp
16         .cfi_restore 5
17         .cfi_def_cfa 4, 4
18         ret
19         .cfi_endproc
20 .LFE0:
21         .size   g, .-g
22         .globl  f
23         .type   f, @function
24 f:
25 .LFB1:
26         .cfi_startproc
27         pushl   %ebp
28         .cfi_def_cfa_offset 8
29         .cfi_offset 5, -8
30         movl    %esp, %ebp
31         .cfi_def_cfa_register 5
32         pushl   8(%ebp)
33         call    g
34         addl    $4, %esp
35         leave
36         .cfi_restore 5
37         .cfi_def_cfa 4, 4
38         ret
39         .cfi_endproc
40 .LFE1:
41         .size   f, .-f
42         .globl  main
43         .type   main, @function
44 main:
45 .LFB2:

然后输入g^.s*/d发现指令不能用,便手动dd删除之得到

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

刚开始对于一下片段在各函数头出现感到困惑

        pushl   %ebp
        movl    %esp, %ebp

在查阅资料后了解到在函数调用过程中,ebp和esp之间的空间被称为本次函数调用的“栈帧”。函数调用结束后,处于栈帧之前的所有内容都是本次函数调用过程中分配的临时变量,都需要被“返还”。这样在概念上,给了函数调用一个更明显的分界。下图是一个程序运行的某一时刻的栈帧图:

另一个问题就是对于所谓的堆栈空间,esp,和ebp作为栈顶和栈底都可以变化,这点与数据结构中严格的堆栈定义有所区别,更有点像队列的,但是因为其作为寄存器保存到是对应内存的地址其实也是合理的。

2.代码对应的汇编执行的过程

函数是从main开始执行的,所以17.18
行建立主函数的堆栈空间,19行将立即数8压入内存中的堆栈空间作为f函数,此时修改了EIP寄存器,指令跳转到第8行f函数处。f函数前两行功能同主函数,第十一行将ebp中保存的堆栈底号加8压入堆栈空间,同时esp下移,此时栈顶指针对应内存空间保存的参数8在下一行call g中被g函数调用。然后g函数在四五行中将计算结果存入eax寄存器中被返回22行,将计算结果加1重新存入eax寄存器中。

原文地址:https://www.cnblogs.com/besti-20199303/p/11569034.html