Linux内核分析之计算机是如何工作的
一、计算机工作原理
本周实验主要是反汇编C代码,生成汇编程序。冯·诺依曼理论的要点是:数字计算机的数制采用二进制,计算机应该按照程序顺序执行。人们把冯·诺依曼的这个理论称为冯·诺依曼体系结构。CPU通过总线从内存中读取一条条程序,根据程序的内容执行具体的步骤。CPU在读取指令时,通过寄存器IP来指向下一条指令(如果是32位系统,则为EIP),CPU的寄存器分为通用寄存器、段寄存器、状态寄存器。可以用一张图来说明
进程是一个可执行程序的实例。从内核角度看,进程由用户内存空间和一系列内核数据结构组成,其中用户内存空间包含了程序代码及代码使用的变量,而内核数据结构用于维护进程状态信息。每个进程分配的内存由很多部分组成。当计算机在运行时,先从内存中取出第一条指令,通过控制器的译码,按指令的要求,从存储器中取出数据进行指定的运算和逻辑操作等加工,然后再按地址把结果送到内存中去。接下来,再取出第二条指令,在控制器的指挥下完成规定操作。依此进行下去。直至遇到停止指令。
计算机的寻址方式老师介绍了以下几种:
movl %eax,%edx edx=eax 寄存器寻址
movl $0x123,%edx edx=0x123 立即寻址
movl 0x123,%edx edx=*(int32_t*)0x123 直接寻址
movl (%ebx),%edx edx=*(int32_t*)ebx 间接寻址
movl 4(%ebx),%edx edx=*(int32_t*)(ebx+4) 变址寻址
二、实验内容
对于简单C语言程序main.c
int g(int x)
{
return x + 4;
}
int f(int x)
{
return g(x);
} int main(void)
{
return f(5) + 1;
}
使用如下命令编译成汇编代码,然后删除汇编代码中用于链接的辅助信息:
gcc –S –o main.s main.c -m32
得到的文件保存在main.s中
g:
pushl %ebp
movl %esp, %ebp
movl (%ebp), %eax
addl $4, %eax
popl %ebp
ret f:
pushl %ebp
movl %esp, %ebp
subl $, %esp
movl (%ebp), %eax
movl %eax, (%esp)
call add
leave
ret main:
pushl %ebp
movl %esp, %ebp
subl $, %esp
movl $5, (%esp)
call f
addl $1, %eax
leave
ret
处理后的汇编代码为:
设空栈如下:
从main开始执行,以下为逐句解释:
最开始的时候ebp和esp都指向标号0的位置
pushl %ebp :ebp入栈,保存当前ebp0,esp-4指向标号1
movl %esp, %ebp :将ebp指向标号1
subl $, %esp :esp-,指向标号2
movl $5, (%esp) :esp指向的栈中标号2对应的地方存储5
call sec :将eip()入栈,esp-4指向标号3,跳转至f执行
接下来执行f中的代码:
pushl %ebp :将ebp()入栈,esp-4指向标号4
movl %esp, %ebp :ebp指向标号4
subl $, %esp :esp-,指向标号5
movl (%ebp), %eax :将ebp指向的地址加八对应地址中的数据放入eax,即标号2对应存储数据5,所以(eax)=5
movl %eax, (%esp) :把eax放入esp对应位置,即栈中标号5对应位置
call g :将eip()入栈,esp-4指向标号6,跳转至g执行
接下来执行g中的代码:
pushl %ebp :ebp()入栈,esp-4指向标号7
movl %esp, %ebp :ebp指向标号7
movl (%ebp), %eax :ebp+8位置中的数据赋给eax,即标号5位置,(eax)=5
addl $4, %eax :eax中数据+4,即5+4=9
popl %ebp :ebp()出栈,即ebp指向标号4,esp+4指向标号6
ret :eip()出栈,esp+4指向标号5,跳转至第16行继续执行
接下来又回到f中继续执行:
leave :把ebp赋给esp,即esp指向标号4,ebp()出栈,esp+4指向标号3,ebp指向标号1
ret :eip()出栈,esp+4指向标号2,跳转至第25行继续执行
接下来回到main中继续执行:
addl $1, %eax :eax中的数据+1,即9+1=10
leave :把ebp赋给esp,即esp指向标号1,ebp()出栈,ebp指向标号0,esp+4指向标号0
ret :此时栈已经空了,恢复最开始的状态,运行结束,最后的结果保存在eax中,为10。
三、 堆栈变化分析
程序从main.s第17行开始运行,CPU的IP寄存器指向汇编代码的第18行,假设堆栈在内存中的地址分别为0,1,2,3……堆栈基指针寄存器(EBP)和堆栈顶指针寄存器(ESP)均指向堆栈段0处。第18~21行首先为main函数开辟新的内存区域,之后将传的参数5入栈,此时堆栈段如下所示:
然后程序调用call 函数,将IP入栈,IP指向代码第9行f处。
在f函数的代码处,首先为f函数开辟新的内存区域,接着将传入的参数5赋值给EAX,并将EAX入栈
程序在此调用call进入g函数。在g函数中,同样先是开辟内存空间,然后将参数传给EAX,并将EAX的值加上4。之后将EBP出栈,并调用ret命令。此时IP重新指向f函数call之后的命令。
之后就是不断的调用leave与ret命令,跳出当前的内存区域,回到上一级函数的内存区域中
ret指令执行后函数g调用完毕,返回。leave指令用于释放一个子例程的栈帧,等价与以下两条指令:
- movl %ebp, %esp
- popl %ebp
并将EAX的值加4,直到跳出main函数,至此程序结束
四、总结
通过本次课程的学习,我掌握了存储计算机工作模型和汇编的基础知识。计算机的基本原理是存贮程序和程序控制。预先要把指挥计算机如何进行操作的指令序列(称为程序)和原始数据通过输入设备输送到计算机内存贮器中。每一条指令中明确规定了计算机从哪个地址取数,进行什么操作,然后送到什么地址去等步骤。
其中,掌握冯·诺依曼体系结构是理解计算机工作原理的要点。按照冯·诺依曼存储程序的原理,计算机在执行程序时须先将要执行的相关程序和数据放入内存储器中,在执行程序时CPU根据当前程序指针寄存器的内容取出指令并执行指令,然后再取出下一条指令并执行,如此循环下去直到程序结束指令时才停止执行。其工作过程就是不断地取指令和执行指令的过程,最后将计算的结果放入指令指定的存储器地址中。
在课程中提到了很多操作系统的内容由于知识结构,我比较欠缺,今后我会加强这方面的知识储备。
刘帅
原创作品转载请注明出处
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
Linux内核分析之计算机是如何工作的的更多相关文章
- Linux内核分析之操作系统是如何工作的
在本周的课程中,孟老师主要讲解了操作系统是如何工作的,我根据自己的理解写了这篇博客,请各位小伙伴多多指正. 一.知识点总结 1. 三个法宝 存储程序计算机:所有计算机基础性的逻辑框架. 堆栈:高级语言 ...
- linux内核分析作业:以一简单C程序为例,分析汇编代码理解计算机如何工作
一.实验 使用gcc –S –o main.s main.c -m32 命令编译成汇编代码,如下代码中的数字请自行修改以防与他人雷同 int g(int x) { return x + 3; } in ...
- 《Linux内核分析》第一周 计算机是如何工作的?
刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK ONE(2. ...
- LInux内核分析——计算机是如何工作的进行
万子惠 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 " 实 ...
- Linux内核分析第一周学习总结:计算机是如何工作的?
韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.冯诺依曼体系 ...
- 《Linux内核分析》第一周笔记 计算机是如何工作的
一.计算机是如何工作的? 1.存储程序计算机工作模型 1)冯诺依曼体系结构 学习研究计算机的基本概念.就是指存储程序计算机.所有的有计算功能的电子设备小到计算器,大到超级计算机核心部分都可以用这种体系 ...
- 《Linux内核分析》第一周学习小结 计算机是如何工作的?
<Linux内核分析>第一周.计算机是如何工作的? 20135204 郝智宇 一.存储程序计算机工作模型 1. 冯诺依曼体系结构: 数字计算机的数制采用二进制:计算机应该按照程 ...
- 《Linux内核分析》 之 计算机是如何工作的
[李行之原创作品 转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] <Linux内 ...
- linux内核分析--计算机是如何工作的
实验部分 使用gcc -S -o main.s main.c -m32命令将源代码编译成汇编代码. 源代码如下: int g(int x) { return x + 9; } int f(int x) ...
随机推荐
- Android dispatchTouchEvent介绍
一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE...->ACTION_ ...
- 嵌入式Linux内核I2C子系统详解
1.1 I2C总线知识 1.1.1 I2C总线物理拓扑结构 I2C总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成.通信原理是通过对SCL和SDA线高 ...
- 扩展运算是个影藏boss
short a =1; a+=1; //实际上是 a=(short)(a+1); 而 short a=1; a=a+1; //不报错,应为进行算术逻辑运算会默认转为int类型,但是你要把int类型赋值 ...
- Http的请求对象
Servlet 客户端 HTTP 请求 当浏览器请求网页时,它会向 Web 服务器发送特定信息,这些信息不能被直接读取,因为这些信息是作为 HTTP 请求的头的一部分进行传输的.您可以查看 HTTP ...
- Log4Net日志的配置
<configuration> <configSections> <section name="log4net" type="log ...
- linux C学习笔记01--makefile
不知不觉毕业五年了,以前学的linux基本都忘了,重新温习起来吧! 下面是自己写的makefile文件,供新手和自己回头时查阅 CC=gcc EXE=c.out CCC=g++ EEE=cc.out ...
- VC++ 用setsockopt()来控制recv()与send()的超时
在send(),recv()过程中有时由于网络状况等原因,收发不能预期进行,而设置收发超时控制: 以下是来自于网上一篇文章中的摘录,它是这样写的: ;//1秒, //设置发送超时 setsockopt ...
- sqlserver 分区表
我们知道很多事情都存在一个分治的思想,同样的道理我们也可以用到数据表上,当一个表很大很大的时候,我们就会想到将表拆 分成很多小表,查询的时候就到各个小表去查,最后进行汇总返回给调用方来加速我们的查询速 ...
- AngularJS学习---更多模板(More Templating) step 8
1.切换分支 amosli@amosli-pc:~/develop/angular-phonecat$ git checkout step- #切换分支 amosli@amosli-pc:~/deve ...
- Hessian 初探
Hessian 是一个序列化协议, 他的优点在于比 Java 原生的对象序列化/反序列化速度更快, 序列化出来以后的数据更小. 序列化协议跟应用层协议无关, 可以将 Hessian 序列化以后的数据放 ...