Linux 内核分析
计 算 机 是 如 何 工 作 的
SG5045 张芸蜻 信安
实验要求:
使用Example的c代码分别生成.cpp,.s,.o和ELF可执行文件,并加载运行,分析.s汇编代码在CPU上的执行过程。通过实验解释单任务计算机是怎样工作的,并在此基础上讨论分析多任务计算机是怎样工作的。
实验内容:
一、C语言的编译过程
C语言的编译主要有4个步骤:
1.预处理:.c-->.cpp
2.编译:.cpp-->.s
3.汇编:.s-->.o
4.链接
现将各个步骤逐一分解详细说明。
1.在linux下编写example.c源代码
2.预处理
概念:在编译之前进行的处理。 C语言的预处理主要有三个方面的内容:(1)宏定义 (2)文件包含; (3)条件编译。 预处理命令以符号“#”开头。
命令:gcc -E -o example.cpp example.c
3.编译
概念:把用高级程序设计语言书写的源程序,翻译成等价的计算机汇编语言或机器语言书写的过程命令:gcc -x cpp-output -S -o example.s example.cpp
汇编代码如下:
.file "example.c"
.text
.globl g
.type g, @function
g:
pushl %ebp //将ebp压栈
movl %esp, %ebp //将esp中的地址赋给ebp
movl 8(%ebp), %eax
addl $3, %eax
popl %ebp
ret
.size g, .-g
.globl f
.type f, @function
f:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call g
leave
ret
.size f, .-f
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl $8, (%esp)
call f
addl $1, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3"
.section .note.GNU-stack,"",@progbits
4.汇编成目标代码
概念:汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令
命令:gcc -x assembler -c example.s -o example.o
二、分析example.s代码在CPU上的执行过程
main函数为程序的入口,栈是向低地址的方向生长的
<
27 | main: | |
28 | pushl %ebp | //将ebp压栈(用ebp1表示) |
<
29 | movl %esp,%ebp | //将esp中的地址赋值给ebp |
<
30 | subl $4,%esp | //将esp向下减4个字节的大小,相当于分配了4字节的栈空间 |
31 | movl $8,(%esp) | //将立即数8放入到esp指向的内存中,作用是压入参数 |
<
32 | call f | //调用函数f,cs : eip指向被调用函数的入口地址,所以这条指令将cs:ip压栈 |
开始执行f 函数:
<
15 | f: | |
16 | pushl %ebp | //将ebp压栈 |
17 | movl %esp,%ebp | //将esp中的地址赋值给ebp(在栈示意图种用ebp2表示) |
<
18 | subl $4,%esp | //将esp向下减4个字节的大小,相当于分配了4字节的栈空间 |
19 | movl $8,(%esp) | //将立即数8放入到esp指向的内存中,作用是压入参数 |
<
20 | call g | //调用函数g,cs : eip指向被调用函数的入口地址,所以这条指令将cs:ip压栈 |
5 | g: | |
6 | pushl %ebp | //将ebp压栈 |
7 | movl %esp,%ebp | //将esp中的地址赋值给ebp(在栈示意图种用ebp3表示) |
<
8 | movl 8(%ebp),%eax | //从ebp+8的位置出取参数,放入到eax寄存器中 |
9 | addl$3,%eax | //将eax中的内容增加3 |
此时,栈并没有改变
<
10 | popl %ebp | 从栈顶取出数据,放入到ebp中 |
<
11 | ret | ret是个宏指令,其功能是从栈顶弹出原来保存在这里的cs : eip的值,放入cs : eip中 |
此时,返回到f函数的第22条指令
<
22 | leave | //leave是宏指令,其相当于 movl %ebp, %esp和popl %ebp |
23 | ret |
再返回执行main的指令第33行
<<
33 | addl $1,%eax | //将eax中的内容加1,eax通常用来做为返回值,所以,eax存储的是调用f后的返回值 |
34 | leave | //相当于movl %ebp, %esp + popl %ebp |
<
35 | ret |
三、实验总结:计算机是如何工作的
计算机实际上是一个取指令执行指令的过程。但计算机并不是完全线性执行下去的,它有跳转指令。跳转是通过修改eip来实现的,因为eip是指向计算机要执行的下一条指令。
多任务计算机:多任务的执行是通过中断的机制来完成的,引入中断信号使得计算机停止执行当前工作转而去执行正常控制流之外的代码。