“Linux内核分析”实验一报告
张文俊 + 原创作品转载请注明出处 + 《Linux 内核分析》 MOOC 课程
实验要求:
1、总结部分要求阐明自己对“计算机是如何工作的”理解;
2、博客中需要使用实验截图;
实验内容:
1、阐述计算机是如何工作的;
2、分析汇编代码的工作过程中堆栈的变化;
一、冯诺依曼体系结构
冯诺依曼体系结构是现代计算机的基础,现在大多计算机仍是冯诺依曼计算机的组织结构,只是作了一些改进而已,并没有从根本上突破冯体系结构的束缚。
根据冯·诺依曼体系结构构成的计算机,必须具有如下功能:
把需要的程序和数据送至计算机中。
必须具有长期记忆程序、数据、中间结果及最终运算结果的能力。
能够完成各种算术、逻辑运算和数据传送等数据加工处理的能力。
能够根据需要控制程序走向,并能根据指令控制机冯· 诺依曼体系结构器的各部件协调操作。
能够按照要求将处理结果输出给用户。
冯诺依曼体系结构有以下三条特点:
(1)计算机处理的数据和指令一律用二进制数表示。
(2)顺序执行程序。
(3)计算机硬件由运算器、控制器、存储器、输入设备和输出设备五大部分组成。
二、实验代码
源C代码如下:
int g(int x)
{
return x + 5;
}
int f(int x)
{
return g(x);
}
int main(void)
{
return f(21) + 5;
}
通过实验楼的已搭建好的 64 位 Linux 虚拟机环境,采用如下命令编译汇编代码:
gcc -S -o main.s main.c -m32
其中,-S表示生成为汇编代码;
-m32表示生成的汇编程序是32位的;
汇编程序后缀为.s
使用上条命令汇编出的main.s文件代码如下: .file "main.c"
.text
.globl g
.type g, @function
g:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
movl 8(%ebp), %eax
addl $5, %eax
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size g, .-g
.globl f
.type f, @function
f:
.LFB1:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call g
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE1:
.size f, .-f
.globl main
.type main, @function
main:
.LFB2:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $4, %esp
movl $21, (%esp)
call f
addl $5, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE2:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
.section .note.GNU-stack,"",@progbits
其中,实际被程序执行的代码如下:
g:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
addl $5, %eax
popl %ebp
ret
f:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call g
leave
ret
main:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl $21, (%esp)
call f
addl $5, %eax
leave
ret
三、汇编代码分析
首先从 main
函数开始:
pushl %ebp
movl %esp, %ebp
表示将基底指针压栈,然后把栈顶指针的值赋给基底指针。
subl $4, %esp
movl $21, (%esp)
由于栈是由高地址向低地址扩展,在 32 位操作系统系统上,每个栈元素为 4 个字节,所以栈顶指针减 4表示栈顶指针减了一个单位(即向下拓展一个单位);
同时,采用立即数寻址的方式,把21 存入栈顶指针所指向的位置。
call f
call
指令调用函数 f 执行,
call指令,相当于pushl %eip movl $f, %eip
即:
首先将当前 %eip 的值压栈保存,然后将f地址赋给eip。
函数 f 类似于main函数,f继续调用g函数。在g函数中,eax的值要增加5 ,然后 popl
出栈返回到先前函数 f 中 call
指令保存执行指令地址。
addl $5, %eax
popl %ebp
函数g返回后,函数 f 的下一条指令 leave
相当于:
movl %ebp, %esp
popl %ebp
它将函数堆栈恢复到当前函数被调用前的状态。
然后执行ret
指令,函数返回。
函数 f 返回后,函数 main 的下一条指令将 eax中的值加5,然后再leave
恢复堆栈状态,ret
返回。
四、总结
计算机的基本工作原理是美籍匈牙利科学家冯`诺依曼于1946年首先提出来的。
其核心是存储程序与控制,即计算机能够自动的完成运算或处理过程的基础是存储程序和程序控制。
计算机之所以能自动,正确的按人们的意图工作,是由于人们事先已把计算机如何工作的程序和原始数据通过输入设备送到计算机的存储器中。
当计算机执行时,控制器就把这些指令一条接一条地从存储器中取出来,加以翻译,并按指令的要求进行相应的操作,直到遇到停止指令或发生计算机无法继续运行的情况为止。
程序中的每一条指令都要求计算机完成一定的操作。一条指令通常由两个部分组成,即地址码(操作码)和操作数。
因为计算机只能识别二进制数,所以每条指令都用二进制编码表示,但直接用二进制编码书写指令不方便,因此常用十六进制形式表示。
五、实验截图