Linux内核分析第一周学习总结:计算机是如何工作的?
2016-02-25 18:04
651 查看
韩玉琪 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
接口
API:应用程序编程接口,程序员<->计算机
ABI:应用程序二进制接口,程序<->CPU
段寄存器
CPU实际取指令的时候根据
立即数寻址(immediate)
直接寻址(direct)
间接寻址(indirect)
变址寻址(displaced)
注:Linux内核使用A&T汇编格式(另有Intel汇编格式)
popl %eax:
call 0x12345:
ret:
enter:
leave
注:由于eip不能被程序员直接修改,所以(*)不能直接使用。
函数调用堆栈是由逻辑上多个堆栈叠加起来的。
ebp和esp这两个寄存器总是指向堆栈的栈底和栈顶,这里所说的是相对的概念。
函数返回值默认存储在%eax寄存器中。
然后 movl %ebp,(%esp) => 将ebp的值放在esp所指向位置,即把“2016”放在2012的位置上。
ebp = 2016,esp = 2012
ebp = 2012,esp = 2012
ebp = 2012,esp = 2008
ebp = 2012,esp = 2008
push %eip => esp向下移到位置2004,把eip(下一条指令所在,即第23行)放在该位置上,然后将fun函数所在赋给eip,执行fun函数的指令。
ebp = 2012,esp = 2004
eax = 2
ebp = 2000,esp = 1996
此时,eax = 2,然后加7,eax = 9。
ebp = 1988,esp = 1988
然后addl $4,%esp => 将esp上移到位置1992。
ebp = 2000,esp = 1992
esp上移到位置1996,指令执行第15行。
ebp = 2000,esp = 1996
然后popl %ebp => ebp指向位置2000存储的值,即位置2012处,esp指向位置2004。
ebp = 2012,esp = 2004
ebp = 2012,esp = 2008
程序:我们一般做的,是告诉计算机操作的步骤、输入的数据是什么、处理后的结果如何存储。然后,计算机会尽可能忠实地按照程序的顺序将每一个操作步骤的指令取出,变成机器语言,通过软硬件协同工作。
汇编语言:汇编语言其实也是机器语言的一种翻译。现在编译器功能优化的比较强大,学习汇编语言真正用的时候并不多,但它是我们分析处理问题的一种角度。能够看懂汇编语句,在分析程序真正执行的流程、单步调试程序的方面都是有帮助的。
一、冯诺依曼体系结构:存储程序计算机
1. 从硬件角度
总线 CPU ============ 内存 - CPU上的IP总指向内存的某一块区域,CPU执行其所指向的指令。
2. 从程序员角度(软件)
内存保存指令和数据,CPU解释执行
接口
API:应用程序编程接口,程序员<->计算机
ABI:应用程序二进制接口,程序<->CPU
二、汇编基础
1. 寄存器
通用寄存器通用寄存器 | ||
---|---|---|
16bit | 32bit | |
AX | eax | 累加器 |
BX | ebx | 基址寄存器 |
CX | ecx | 计数寄存器 |
DX | edx | 数据寄存器 |
BP | ebp | 堆栈基址指针 |
SI | esi | 变址寄存器 |
DI | edi | 变址寄存器 |
SP | esp | 堆栈顶指针 |
段寄存器 | |
---|---|
CS | 代码段 |
BS | 数据段 |
ES | 附加段 |
SS | 堆栈段 |
FS | 附加段 |
GS | 附加段 |
cs:eip来准确定位一个指令
2. 几种寻址方式
寄存器寻址(register)例:movl %eax,%edx <=> edx=eax
立即数寻址(immediate)
例:movl $0x123,%edx <=> edx=0x123
直接寻址(direct)
例:movl 0x123,%edx <=> edx=*(int32_t*)0x123
间接寻址(indirect)
例:movl (%ebx),%edx <=> edx=*(int32_t*)ebx
变址寻址(displaced)
例:movl 4(%ebx),%edx <=> edx=*(int32_t*)(ebx+4)
注:Linux内核使用A&T汇编格式(另有Intel汇编格式)
3. 常见指令
pushl %eax:subl $4,%esp movl %eax,(%esp)
popl %eax:
movl (%esp),%eax addl $4,%esp
call 0x12345:
pushl %eip (*) movl $0x12345,%eip (*)
ret:
popl %eip (*)
enter:
pushl %ebp movl %esp,%ebp
leave
movl %ebp,%esp popl %ebp
注:由于eip不能被程序员直接修改,所以(*)不能直接使用。
函数调用堆栈是由逻辑上多个堆栈叠加起来的。
ebp和esp这两个寄存器总是指向堆栈的栈底和栈顶,这里所说的是相对的概念。
函数返回值默认存储在%eax寄存器中。
二、汇编代码的分析
1. main.c代码
2. 汇编代码
gcc -S -o main.S main.c -m32 -S:仅汇编 -m32:生成32位的指令格式
3. 分析
初始状态:从main开始执行
假设起始地址为2016,%ebp、%esp都指向2016。第18行:pushl %ebp
相当于先执行 subl $4,%esp => esp指向2012;然后 movl %ebp,(%esp) => 将ebp的值放在esp所指向位置,即把“2016”放在2012的位置上。
ebp = 2016,esp = 2012
第19行:movl %esp,%ebp
ebp指向与esp相同的位置2012上。ebp = 2012,esp = 2012
第20行:subl $4,%esp
esp减4,即向下移动到位置2008上。ebp = 2012,esp = 2008
第21行:movl $2,(%esp)
把立即数2放在esp所在位置2008上。ebp = 2012,esp = 2008
第22行:call fun
调用函数funpush %eip => esp向下移到位置2004,把eip(下一条指令所在,即第23行)放在该位置上,然后将fun函数所在赋给eip,执行fun函数的指令。
ebp = 2012,esp = 2004
第8行:跳转到fun的初始状态
ebp = 2012,esp = 2004第9行:push %ebp
ebp = 2012,esp = 2000第10行:movl %esp,%ebp
ebp = 2000,esp = 2000第11行:subl $4,%esp
ebp = 2000,esp = 1996第12行:movl 8(%ebp),%eax
第13行:movl %eax,(%esp)
将(ebp+8)即位置2008存放的值通过eax放在esp位置1996上eax = 2
ebp = 2000,esp = 1996
第14行:call add
ebp = 2000,esp = 1992第1行:跳转到add的初始状态
ebp = 2000,esp = 1992第2行:pushl %ebp
ebp = 2000,esp = 1988第3行:movl %esp,%ebp
ebp = 1988,esp = 1988第4行:movl 8(%ebp),%eax
第5行:addl $7,%eax
将(ebp+8)即位置1996处存放的值赋给eax;此时,eax = 2,然后加7,eax = 9。
ebp = 1988,esp = 1988
第6行:popl %ebp
相当于先movl (%esp),%ebp => 把esp位置1988存放的值赋给ebp,ebp指向2000。然后addl $4,%esp => 将esp上移到位置1992。
ebp = 2000,esp = 1992
第7行:ret
相当于popl %eipesp上移到位置1996,指令执行第15行。
ebp = 2000,esp = 1996
第15行:leave
相当于先movl %ebp,%esp => 将esp指向ebp,即位置2000。然后popl %ebp => ebp指向位置2000存储的值,即位置2012处,esp指向位置2004。
ebp = 2012,esp = 2004
第16行:ret
ebp = 2012,esp = 2008第23行:addl $3,%eax
eax加3,eax = 12ebp = 2012,esp = 2008
第24行:leave
ebp = 2016,esp = 2016第25行:ret
回到执行main之前的位置寄存器内容变化
三、总结:关于计算机是如何工作的
复杂又简单的计算机:计算机能实现许多看起来很复杂的功能,计算和处理大量的数据,但是,它实现这些复杂功能是不断地重复大量既定的简单的操作。程序:我们一般做的,是告诉计算机操作的步骤、输入的数据是什么、处理后的结果如何存储。然后,计算机会尽可能忠实地按照程序的顺序将每一个操作步骤的指令取出,变成机器语言,通过软硬件协同工作。
汇编语言:汇编语言其实也是机器语言的一种翻译。现在编译器功能优化的比较强大,学习汇编语言真正用的时候并不多,但它是我们分析处理问题的一种角度。能够看懂汇编语句,在分析程序真正执行的流程、单步调试程序的方面都是有帮助的。
相关文章推荐
- android AsyncHttp的简单使用与封装
- HTTP Live Streaming直播(iOS直播)技术分析与实现
- Java 网络编程(四) InetAddress类
- 在mac上开启httpServer服务
- 从TCP协议的原理来谈谈rst复位攻击
- HTTP method POST is not supported by this URL
- CocoaAsyncSocket 网络通信使用之Protobuf安装(五)
- 编译安装http启动问题
- 深入理解Hadoop集群和网络
- 深入浅出Cocoa之Bonjour网络编程
- RTSP协议、RTMP协议、HTTP协议的区别
- c语言客户端与golang服务端通信(网络字节序)
- okhttp请求Demo
- centos minimal 网络配置详细解读
- 解决apache启动错误"httpd:Could not reliably determine
- 栈和堆的数据结构的差异
- 计算机网络12--TCP/IP参考模型
- HTTP协议(二):header标头说明
- 反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的
- HTTP协议(一):介绍