20135205信息安全系统设计基础第五周学习总结

第三章:程序的机器级表示

第一节:历史观点

Intel处理器系列俗称x86,经历了一个长时期的、不断进化的发展过程。

8086是第一代单芯片、十六位微处理器之一。增加了一个8位外部总线最初的机器型号有32768字节的存储器和两个软驱。

到目前的Core i7:既支持超线程,又是多核,最初的版本支持每个核上执行两个程序,每个芯片上最多四个核。

每个后继处理器的设计都是后向兼容的——较早版本上的代码可以在较新的处理器上运行。

平坦寻址方式:使程序员将整个存储空间看做一个大的字节数组。

第二节:程序编码

1、指令集体系结构(ISA):机器级程序的指令的格式和行为,它定义了处理器状态、指令的格式,以及每条指令对状态的影响。

2、机器级程序使用的存储器地址是虚拟地址:提供的存储器模型看上去是一个非常大的字节数组。

3、IA32机器代码和原始的C代码差别非常大。一些通常对C语言程序员隐藏的处理器状态是可见的:

                   程序计数器(CS:IP)(在IA32中通常称为PC,用%eip表示)指示将要执行的下一条指令在存储器中的地址。

                   理解:当执行一条指令时,首先需要根据PC中存放的指令地址,将指令由内存取到指令寄存器中,此过程称为“取指令”。与此同时,PC中的地址或自动加1或由转移指针给出下一条指令的地址。

        此后经过分析指令,执行指令。完成第一条指令的执行,而后根据PC取出第二条指令的地址,如此循环,执行每一条指令。(出自维基百科)

                   整数寄存器(AX,BX,CX,DX):文件包含8个命名的位置,分别存储32个值。存储地址(对于C语言的指针)或整数数据。

                   条件寄存器(OF,SF,ZF,AF,PF,CF):保存着最近执行的算法或逻辑指令的状态信息。用来实现控制或数据流中的变化,比如用来实现if或while。

                   一组浮点寄存器存放浮点数据。

4、反汇编

1)代码示例:code.c

Int accum = 0;

Int sum (int x, int y)

{

         Int t = x + y ;

         accum += t ;

         return ;

}

命令行:

gcc –S code.c 就能得到汇编代码

这会使GCC产生一个汇编文件code.s

汇编代码文件包含各种声明:

 

 

 

 

sum :

         pushl         %ebp

         movl %esp, %ebp

         movl 12(%ebp), %eax

         addl           8(%ebp), %eax

         addl           %eax, accum

         popl           %ebp

         ret

命令行: gcc –c code.c

GCC编译并汇编该代码

产生code.o,二进制格式无法直接查看。

2)反汇编器

命令行:

Objdump –d code.o

可以查看目标代码文件的内容

有些输出内容过多,我们可以使用 more或less命令结合管道查看,也可以使用输出重定向来查看
od code.o | more
od code.o > code.txt

3)机器代码和它的反汇编表示的特性值注意:

IA32指令长度从1到15个字节不等。

设计指令格式的方式是,从某个给定位置开始,可以将字节唯一地解码成机器指令。

反汇编只是基于机器代码文件中的字节序列来确定汇编代码。它不需要访问程序的源代码或汇编代码。反汇编器使用的指令命名规则与GCC生产的汇编代码使用的有些细微的差别。

4)注释格式

以“.”开头的行都是指导汇编器和链接器的命令。可以忽略。

了解Linux和Windows的汇编格式有点区别:ATT格式和Intel格式:

后者代码省略了指示大小的后缀。指令mov不是movl

后者代码省略了寄存器名字前面的%。如esp而不是%esp

后者代码用不同的方式描述存储器中的位置。

在带有多个操作数的指令情况下列出指令数的顺序相反。

第三节:数据格式

C声明

Intel数据类型

汇编代码后缀

大小(字节)

Char

字节

B

1

Short

W

2

Int

双字

1

4

Long int

双字

l

4

Long long int

-

-

4

Char *

双字

l

4

Float

单精度

S

4

Double

双精度

l

8

Long double

扩展精度

t

10/12



大多数GCC生产的汇编代码指令都有一个后缀,表明操作数的大小。

例如:

Movb(传送字节)、movw(传送字)和movl(传送双字节)。

第四节:访问信息

1、esi edi可以用来操纵数组,esp ebp用来操纵栈帧。
通用寄存器中的eax,ebx,ecx,edx,大家要理解32位的eax,16位的ax,8位的ah,al都是独立的。有可能发生溢出,最高位丢失。

2、有效地址的计算方式 Imm(Eb,Ei,s) = Imm + R[Eb] + R[Ei]*s
大多数指令有一个或多个操作数指令有一个或多个操作数,指示出执行一个操作中药引用的源数据值,以及放置结果的目标位置。各种不同的操作数的可能性被分为三种类型

立即数:也是常数值,书写方式是“$”后面跟一个用标准C表示法表示的整数。任何能放进一个32位的字里的数值都可以用作立即数。

寄存器:表示某个寄存器的内容,对双字操作来说,可以是8个32位寄存器中的一个(例如%eax),对字操作来说,可以是8个16位寄存器中的一个(例如:%ax),或者对字节操作来说可以使8个单字节寄存器元素中的一个(例如:%al)。

存储器引用:根据计算的地址(有效地址)访问某个存储器位置。M[Addr]表示对存储器中从地址Addr开始的b个字节值得引用。注释:M有下角标b,为了简便可省去。

3、数据传送指令

指令

效果

描述

MOV      S、D

D<-S

传送

MOVS     S、D

D<-符号扩展(S)

传送符号扩展的字节

MOVZ     S、D

D<-零扩展(S)

传送零扩展的字节

MOVS和MOVZ指令类都是将一个较小的源数据复制到一个较大的数据位置,高位用符号位扩展(用原值的最高位数值进行填充)或零扩展(高位用0填充)进行填充。

Push:把数据压入栈中

Pop:删除数据,弹出数据。

栈顶元素的地址是所有栈中元素地址中最低的。
第五节:算法和逻辑操作

目的操作数必须是一个寄存器。

指令             效果           描述

Lead S,D        D<-&S      加载有效地址

SUB  S,D        D<-D-S      减

第六节:控制

1)  条件码

条件码:CPU维护着一组单个位的条件码寄存器

2)访问条件码

根据条件码的某个组合将一个字节设置为0或者1;

可以条件跳转到程序的某个其他的部分;

可以有条件地传送数据;

3)跳转指令机器及其编码

Jmp.L1

.L1:

会导致程序跳过两个命令间的指令


4)有条件跳转的条件看状态寄存器(条件码寄存器)。

if else汇编结构:汇编器为then-statement和else-statement产生各自的代码块。它会插入条件和无条件分支,以保证能执行正确的代码块。

do-while:

loop

body-statement

while(test-expr);

这个循环的效果就是重复执行body-statement,对est-expr求值,如果求值结果非0则继续循环。

Loop

 body-statement

if(t)

goto loop

汇编结构:

.L2:

 

jg           .L2:
while、for:汇编结构都是将循环转化成goto结构,在转化成汇编结构,与do-while相似。

5)switch语句

通过跳转访问代码位置。

第七节:过程

1)IA32通过栈来实现过程调用,一个1调用包括将数据(以过程参数和返回值的形式)和控制从代码的一部分传递到另一部分。

为单个过程分配的那部分栈成为栈帧。寄存器%ebp为帧指针,寄存器%esp为栈指针。

程序运行时栈指针可以移动,因此大多数信息的访问都是相对于帧指针的。

2)call指令:有一个目标,即指明被调用过程起始的指令地址。

                 效果为将返回地址入栈。

Call/ret函数说明:call指令将控制转移到一个函数的起始,而ret指令返回到call指令后的那个指令。函数返回值存在%eax中




posted @ 2015-10-11 22:15  赤炎亓  阅读(224)  评论(3编辑  收藏  举报