您的位置:首页 > 编程语言

程序的机器级表示(2)--IA32汇编代码

2017-08-01 09:21 211 查看

IA32的整数寄存器

一个IA32中央处理单元(CPU)包含一组8个储存32位值的寄存器。这些寄存器储存整数数据和指针。如下图,字节操作指令可以独立地读写前四个寄存器的2个低位字节。



操作数指示符

大多数指令都会有一或多个操作数,用以指示出执行一个操作中要引用的源数据值以及放置结果的目标位置。IA32支持多种操作数格式,各种操作数的可能性包括三种类型:

立即数,即常数值。立即数的书写方式是‘$’后面跟一个用标准C表示法表示的整数,如$-577或$0x1F.

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

储存器,它会根据计算出来的地址(有效地址)访问某个储存器位置。



在上表中,Imm表示立即数,E表示寄存器,R表示寄存器里的值,M表示内存。

数据传送指令

将数据从一个位置复制到另一个位置的指令的指令是最频繁使用的指令。IA32常用的汇编代码指令如下:



MOV类的指令将源操作数的值复制到目的操作数中。源操作数指定的值是一个立即数,存储在寄存器中或存储器中。目的操作数制定一个位置,要么是一个寄存器,要么是一个存储器地址。但是IA32规定,传送指令的两个操作数不能都指向存储器位置。

栈指针

栈空间向下生长,即栈顶的元素的地址是栈中所有地址的最小值。栈顶指针总是存放在寄存器 %esp中。将一个双字压入栈中,即:

pushl %ebp


将一个双字值压入栈中,首先要将栈指针减4,然后将值写到新的栈顶地址。因此上述指令等价于一下两条指令:

subl %4,%esp
movl %ebp,(%esp)


它们的区别在目标代码pushl指令编码为1个字节,而上面两条指令一共需要6个字节。相反的,弹出一个双字相当于首先将栈顶指针的数据传到目的地址,然后将栈顶指针加4。 因为栈和程序代码使用相同的存储器,所以程序可以使用标准的存储器寻址方法,访问栈当中的任何一个数据。

算术和逻辑操作

下面是一些整数和逻辑操作。



加载有效地址指令leal从存储器读数据到寄存器,但实际上它没有引用寄存器,它的第一个操作数看上去是一个存储器引用,但该指令并不是从制定的位置读取数据,而是将有效地址写入目的操作数。如假设寄存器%eax的值为x,则执行leal 6(%eax),%edx,%edx的值是x+6。

第二组的指令是一元操作,只有一个操作数,既是源也是目的。可以是寄存器,也可以使存储器。

第三组的指令是二元操作,其中,第二个操作数既是源又是目的。两个操作数不能同时是存储器位置。

第三组是移位操作,先给出移位量,再给出移位的数值。移位量是单个字节编码,可以是立即数或放在单字节寄存器元素%cl中。

特殊的算数运算

下图描述的指令支持产生两个32位数字的全64位乘积以及整数除法。



控制(执行指令转移)

机器代码提供两种基本的低级机制来实现有条件的行为:测试数据值,然后根据测试值的结果来改变控制流或数据流。用jump指令可以改变一组机器代码指令的执行顺序。

条件码

CPU除了整数寄存器外还维护着一组单个位的条件码寄存器,它们描述了最近的算数或逻辑操作的属性,可以检测这些寄存器来执行条件分支指令。条件码有:

CF:进位标记。用来检测无符号操作是否溢出

ZF:零标记。最近的操作得出的结果为0

SF:符号标记。最近的操作得到的结果为负数

OF:溢出标记。最近的操作导致一个补码溢出-正溢出或负溢出

除了算术操作会改变条件码外,有两类指令只改变条件码而不改变其它寄存器。如下图所示:



访问条件码

条件码不能直接被读取,常用的使用方法:

可以根据条件码的某个组合,将一个字符设置为0或者1

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

可以有条件地传送数据

第一类的指令称为SET指令,如下:



第二类的指令称为跳转指令,如下



第三类为条件传送指令,如下:

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