您的位置:首页 > 其它

chap3: 程序的机器级表示

2011-06-24 22:06 344 查看
3.2、程序编码

1、对机器级编程而言,两种抽象尤为重要:1)指令集体系结构(Instruction set architecture,ISA;2)虚拟地址;

2、程序存储器包含:可执行代码,OS的一些信息,运行时栈,堆;

3.3、数据格式:

1、Intel IA32用术语“字”(word)表示16位,“双字”(double words)表示32位,“四字”(quad words)表示64位;

3.4、访问信息

1、一个IA32 CPU 包含一组8个存储32位值得寄存器 ,

通用寄存器:eax, ecx, edx, ebx, esi, edi, (ax,cx,...di表示低16位寄存器 ,ax,cx,dx,bx又可以单独使用高八位和第八位,如ah,al)

栈帧寄存器:esp, ebp ;栈帧的最顶端以两个指针来界定,ebp为帧指针,esp为栈指针 (P149)

eax,ecx,edx被划分为”调用者寄存器“,ebx,esi,edi被划分为”被调用者寄存器“;(P151)

2、寻址方法:

立即数寻址: movl 8,eax;

寄存器寻址: movl ebx,eax;

存储器寻址:包括 绝对寻址,间接寻址,基址寻址,变址寻址,比例变址寻址;

绝对寻址 : movl (0x01f0) ,eax; 间址寻址:movl (ebx),eax;

基址寻址 : movl (ebx+2) , eax; 变址寻址:movl (ebx+ecx),eax;

比例变址寻址: movl (4*ebx+2),eax;

3、在IA32中,程序栈存放在存储器的某个区域,入栈时(pushl)栈地址向低地址方向增长,栈顶元素的地址是所有栈中元素地址最低 的,即:在C中,同 一代码块,先定义的变量地址比后定义的变量地址高。

3.5~3.6:讲述了汇编中的算术和逻辑操作,控制(条件,循环,选择(switch)),由于因为我x86汇编在大学时候学的还行,这两节没有细 读,以后用到时再回头复习。

3.7、过程调用(重点)

1、栈帧结构:栈用来传递参数、存储返回信息、保存寄存器、本地存储。过程P(调用者)调用过程Q(被调用者),Q的参数放在P的 栈帧中,P中的返回地址被压入栈中,形成P的栈帧的末尾。过程Q也用栈来保存其它不能存放在寄存器中的局部变量。



2、转移控制:

call指令的效果是将返回地址入栈,并跳转到被调用过程的起始处。返回地址是在程序中紧跟在call后面的那条指令的地址。ret指 令从栈中弹出地址,并跳转到这个位置。

3、寄存器使用惯例:

a: 程序寄存器是唯一能被所有过程共享的资源。eax,ecx,edx被划分为”调用者寄存器“,当过程P调用Q时,Q可以覆盖这些寄存 器,而不会破会任何P所需要的数据;ebx,esi,edi被划分为”被调用者寄存器“,Q必须在覆盖这些寄存器之前,先把它们保存到 栈中(可以是保存到的帧中,也可以是Q的帧的中),在在返回前回复它们;

b: P调用Q时,必须保存ebp和esp;

c: 参数在栈上传递给函数,可以从栈中用相对于ebp的正偏移量来访问它们;可以用push指令或是从栈指针中减去偏移量来在栈上 分配空间;在返回前,函数必须将栈恢复到原始条件,可以恢复所有的被调用者保存寄存器和ebp,并且从这esp是其指向返回地 址。

4、递归过程

a:每个调用在栈中都有它自己的私有空间(保存的返回位置,栈指针和被调用者保存寄存器的值),多个未完成调用的局部变量不 会相互影响。

b:当过程被调用时分配局部存储,当返回是释放存储。

有关递归的资料,参见:http://www.cnblogs.com/jnje/archive/2011/04/09/2010637.html

3.9、异质数据结构:

机器代码不包含关于字段声明或字段名字的信息,即缺乏类型信息。

联合:用不同的字段来引用相同的存储块。

有关联合的使用例子:

]#include<stdio.h>
unsigned float2bit(float f)   //打印float的位模式,位模式即浮点数的用二进制表示的,
{                           //整个函数等价于:return (int)*(int*)&f;
union{
float f;
unsigned u;
} temp;
temp.f = f;
return temp.u;

}
double bit2double(unsigned word0,unsigned word1)
{                           //以两个4字节的unsigned的位的形式,创建一个8字节的double
union{
double d;
unsigned u[2];
}temp;
temp.u[0] = word0;
temp.u[1] = word1;
return temp.d;
}
float bit2float(unsigned word0)
{                           //以1个4字节的unsigned的位的形式,创建一个4字节的float
union{
float d;
unsigned u;
}temp;
temp.u = word0;
return temp.d;
}
int main()
{
float f = 12345;
char s[10] = " ";
printf("%x/n",float2bit(f));     //打印浮点数12345的位模式,结果为:0x4640e400

unsigned w0 = 0x0, w1= 0x40c81c80;
double d = bit2double(w0,w1);  //打印未模式0x0000000040c81c80对应的double类型,结果为:12345.000000
printf("%f/n",d);
unsigned w3 = 0x4640e400;
float ff = bit2float(w3);
printf("%f/n",ff);     //  打印位模式0x4640e400对应的float类型,结果为:12345.000000
return 0;
}


3.9.3 数据对齐:

参见 http://blog.csdn.net/Microsues/archive/2011/01/14/6140329.aspx

3.12 存储器的越界引用和缓冲区溢出:

1、对越界的数组元素的写操作会破坏存储在栈中的状态信息,当程序使用这个破坏的状态,试图重新加载寄存器或执行ret指令时,就 会 发生严重的错误。一种特别常见的破坏状态称为:缓冲区溢出(buffer overflow)。

P177的例子很详细的说明了这种破坏带来的后果。

缓冲区溢出的一个更加致命的后果就是让程序执行它本来不愿意执行的函数。这是一种最常见的网络攻击系统的方法。

2、对抗缓冲区溢出攻击

栈随机化:地址空间随机化(Address-Space Layout Randomization,ASLR)

破坏栈检测:栈保护者、金丝雀(canary)值、哨兵值(guard value)

限制可执行代码区域
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: