程序的机器级表示
来源:互联网 发布:网络机柜 编辑:程序博客网 时间:2024/05/16 17:54
硬着头皮来看一遍深入理解计算机系统,对其中章节进行做个笔记,其中有些一知半解的希望这次是真的懂来
1、程序的过程:从源文件到目标文件的过程
1.1 hello.c
1.2 hello.i 预处理阶段,将#开头的头文件进行展开,宏定义替换
1.3 hello.s 编译阶段,将hello.i文件翻译成汇编程序
1.4 hello.o 通过汇编器as将程序生成为可重定位的二进制的目标程序
1.5 hello 通过链接器生成可执行的目标程序
2. 存储设备
更小更快更贵,更大更慢更便宜
寄存器--》高速缓存l1--》高速缓存l2--》高速缓存ln--》主存--》本地磁盘--》远地磁盘
3. 类型大小
32位下
short int是2字节,long是4字节,long long才是8字节,char*是4字节
64位下
long是8字节,long long也是8字节,char* 是8字节
4.小端法,大端法
比如int类型下,内存值从小到大为
01 23 45 67
如果是小端法,则这个值是0x67452301,大端法这个值则是0x01234567。linux和windows目前都是采用小端法
5. 移位
移位分为算术右移和逻辑右移,就是符号位的问题,如果是算术右移,符号位需要继续保持不变,而逻辑右移则是在最右边补0即可
6.程序的机器级表示,是本次的重点内容来,主要是看懂了一些汇编的基础知识,寄存器的使用
%eip 表示要执行的下一条指令
%esp 栈顶指针
$ebp the temp data,always get data from esp, because esp is always change, we want to use esp data,so we set the esp to ebp for compute
还有寄存器的取值说明,比如直接寻址,间接寻址,立即数寻址,不再列出,下面以实际代码来进行说明
int decode1(int* xp, int* yp, int* zp)
{
int y = *yp;
int z = *zp;
int x = *xp;
*yp = x;
*zp = y;
*xp = z;
int ttt = 0;
return ttt;
}
int main()
{
int xp = 0;
int yp = 1;
int zp = 2;
decode1(&xp, &yp, &zp);
return 0;
}
展开对应的汇编,未经过优化的,使用gcc -o1即可,下面详细解释下各个行代码
08048456 <main>:
8048456: 55 push %ebp //保存ebp,即将ebp入栈,入桟后esp会往下减4,因为ebp占4个字节,桟底的值要小一点
8048457: 89 e5 mov %esp,%ebp // 将esp的值保存到ebp中,因为ebp已经入桟保存好了,所以覆盖ebp寄存器的值也是可以的
8048459: 83 ec 1c sub $0x1c,%esp // 将esp减去28,此处减去的值是为来在esp以下放临时变量,想要看减去来多少值,可以查看esp和ebp的差即可
804845c: c7 45 f4 00 00 00 00 movl $0x0,-0xc(%ebp) 将0保存到r(ebp-12)这个位置, $0x0是立即寻址,即直接取值,如果是0x0这样就是直接寻址,需要取地址对应的内容了
8048463: c7 45 f8 01 00 00 00 movl $0x1,-0x8(%ebp) 将1保存到r(ebp-8)这个位置,就是说ebp-8里面存放的这个地址,这个地址对应的值是1
804846a: c7 45 fc 02 00 00 00 movl $0x2,-0x4(%ebp) 将2保存到ebp-4这个位置
8048471: 8d 45 fc lea -0x4(%ebp),%eax 取ebp-4的内容保存到eax中,eax中存放的是ebp-4这个值,ebp-4这个地址对应的内容是2
8048474: 89 44 24 08 mov %eax,0x8(%esp) eax赋值给esp+8,就是将zp的地址赋值给esp+8,即esp上面是参数,esp下面是本地临时变量
8048478: 8d 45 f8 lea -0x8(%ebp),%eax
804847b: 89 44 24 04 mov %eax,0x4(%esp)
804847f: 8d 45 f4 lea -0xc(%ebp),%eax
8048482: 89 04 24 mov %eax,(%esp) 与上面一样来,将xp的地址赋值给esp
8048485: e8 8a ff ff ff call 8048414 <decode1> 此处会将esp-4,留了4个地址来放什么内容?存放的是eip的值,所以第一个参数就变成来esp+4了
804848a: b8 00 00 00 00 mov $0x0,%eax
804848f: c9 leave
8048490: c3 ret
8048491: 66 90 xchg %ax,%ax
8048493: 66 90 xchg %ax,%ax
8048495: 66 90 xchg %ax,%ax
8048497: 66 90 xchg %ax,%ax
8048499: 66 90 xchg %ax,%ax
804849b: 66 90 xchg %ax,%ax
804849d: 66 90 xchg %ax,%ax
804849f: 90 nop
08048414 <decode1>:
8048414: 55 push %ebp ebp入桟,esp又会减少4,因为esp总是指向桟的最顶端,所以第一个参数本来是+4的,需要+8了
8048415: 89 e5 mov %esp,%ebp
8048417: 83 ec 10 sub $0x10,%esp esp-16,为了保存下面的临时变量
804841a: 8b 45 0c mov 0xc(%ebp),%eax // ebp+12,就是第二个参数
804841d: 8b 00 mov (%eax),%eax
804841f: 89 45 f0 mov %eax,-0x10(%ebp) esp-16用来放临时变量
8048422: 8b 45 10 mov 0x10(%ebp),%eax // ebp+16就是第三个参数
8048425: 8b 00 mov (%eax),%eax
8048427: 89 45 f4 mov %eax,-0xc(%ebp)
804842a: 8b 45 08 mov 0x8(%ebp),%eax // ebp+8就是第一个参数
804842d: 8b 00 mov (%eax),%eax
804842f: 89 45 f8 mov %eax,-0x8(%ebp)
8048432: 8b 45 0c mov 0xc(%ebp),%eax
8048435: 8b 55 f8 mov -0x8(%ebp),%edx
8048438: 89 10 mov %edx,(%eax)
804843a: 8b 45 10 mov 0x10(%ebp),%eax
804843d: 8b 55 f0 mov -0x10(%ebp),%edx
8048440: 89 10 mov %edx,(%eax)
8048442: 8b 45 08 mov 0x8(%ebp),%eax
8048445: 8b 55 f4 mov -0xc(%ebp),%edx
8048448: 89 10 mov %edx,(%eax)
804844a: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
8048451: 8b 45 fc mov -0x4(%ebp),%eax eax是用来存放返回值的
8048454: c9 leave leave所做的事情是还原esp,还原ebp:它等效与如下两句话:movl %ebp %esp,popl %ebp
8048455: c3 ret ret执行的是pop %eip,$eip会存放调用函数处的下一跳语句,每执行一条语句eip都会指向下一条要执行的语句,函数调用前,会先将eip入桟保存,ret再出桟
以上应该就算告一段落来,需要跟踪代码发现步步是怎么回事,另外介绍一下gdb下调试汇编
display /i $eip 需要有这句话,即每次都显示eip的值,ni才有效果,ni就是跟踪汇编一行
i r $esp查看对应寄存器的值
x 0x123,0x123这个地址下对应的值
p *0x123,与上面这个效果一样
disassemble /m main 显示main函数的汇编,并且也显示源代码,这样就能根据汇编地址打断点来
b main
b *0x123,在地址123上打断点
根据上面这些命令,每步执行后,再看各个寄存器的值,就知道上面解释的所以然了
- 程序的机器级表示
- 程序的机器级表示
- 程序的机器级表示
- 程序的机器级表示
- 程序的机器级表示
- 程序的机器级表示
- 程序的机器级表示
- 程序的机器级表示
- 程序的机器级表示
- 程序的机器级表示
- 程序的机器级表示
- 程序的机器级表示
- 程序的机器级表示
- 程序机器级表示
- chap3: 程序的机器级表示
- 程序的机器级表示(一)
- 程序的机器级表示(二)
- 第三章 程序的机器级表示
- 框架知识(2)--iBatis基础知识
- 破译A盾禁止加载驱动失效之谜
- 数据结构上机测试2-2:单链表操作B
- rsync 使用示例
- STL 简单 vector 的实现
- 程序的机器级表示
- 软件工程(十一)
- RecycleView的分割线之私人订制
- POJ 1442 Black Box(treap树指针实现)
- 数据挖掘算法---KNN(附python代码)
- ActionBar编写方法
- C# + Socket断线重连 整理
- Scala学习记录-Scala Windows环境搭建
- poj3468 A Simple Problem with Integers(成段更新)