算数和逻辑操作

来源:互联网 发布:iphone投影到mac 编辑:程序博客网 时间:2024/05/17 01:07

指令类ADD由三条加法指令组成:addb, addw, addl, 分别是字节加法,字加法和双字加法。
事实上,每个指令类都有对字节,字和双字数据进行操作的指令。这些操作被分为四组:加载有效地址,一元操作,二元操作,移位。

加载有效地址:

加载有效地址(load effective address)指令leal实际上是movl的变形。它的指令形式是从存储器读数据到寄存器,但实际上没有引用存储器。它的第一个操作数看上去是一个存储器引用,但该指令并不是从指定的位置读入数据,而是将有效地址写入到目的操作数。

eg:
如果寄存器%eax的值为x,那么指令leal 7(%edx, %edx, 4),%eax将设置寄存器%eax的值为5x+7.

加载有效地址指令(leal)通常用来执行简单的算术操作。

一元操作和二元操作:

一元操作:只有一个操作数,既是源又是目的,这个操作数可以是一个寄存器,也可以是一个存储器位置。
eg:指令incl(%esp)会使栈顶的4字节元素加1,与C语言的自增,自减操作符有点类似。

二元操作:第二个操作数既是源又是目的,与C语言的赋值运算符类似,例如x+=y;不过,要注意,源操作数是第一个,目的操作数是第二个。

eg:指令subl %eax, %edx
使寄存器%edx的值减去%eax的值。
第一个操作数可以是立即数,寄存器或者存储器位置,第二个操作数可以是寄存器或者存储器位置。和movl指令一样,两个操作数不能同时是存储器位置。

移位操作:
移位操作,先给出移位量,然后第二项给出要移位的位数,它可以进行算数和逻辑右移。移位量用单个字节编码,因为只允许0到31位的移位(只考虑移位量的低五位)。
移位量可以是一个立即数,或者放在单字节寄存器元素%cl中。

左移指令有两个名字:SAL和SHL,两者效果一样,都是将右边填上0;右移指令不同,SAR执行算术移位(填上符号位),而SHR执行逻辑移位(填上0),移位操作的目的操作数可以是一个寄存器或者是一个存储器位置。

下来看一个执行算术操作的函数:
源代码:

int arith(int x, int y, int z){     int t1 = x + y;    int t2 = z * 48;    int t3 = t1 & 0xFFFF;    int t4 = t2 * t3;    return t4;}

汇编代码:
这里写图片描述

汇编指令与源代码中顺序不同。指令4和指令5用leal和移位指令的组合来实现表达式z*48,第七行计算x+y的值,第八行计算t1和0xFFFF的AND值,第八行执行最后的乘法。

特殊的算术操作:
imull指令:“双操作数”乘法指令,从两个32位操作数产生一个32位乘积。(补码乘法)

mull指令:无符号数乘法
这两个指令都要求一个参数必须在寄存器%eax中,而另一个作为指令的源操作数给出,然后乘机存放在寄存器%edx(高32位)和%eax(低32位)中。

eg:假设有符号数x和y存储在相对于%ebp偏移量为8和12的位置,我们希望把他的全64位乘积作为8个字节存放在栈顶。代码如下:

movl  12(%ebp),   %eaximull   8(%ebp)movl   %eax,  (%esp)movl   %edx,  4(%esp)

小端机器:寄存器%edx中的高位存放在相对于%eax中的低偏移量为4的地方。栈是向低地址方向增长的,也就是说低位在栈顶。

Idivl:有符号除法指令将寄存器%edx(高32位)和%eax(低32位)中的64位数作为被除数,而除数作为指令的操作数给出。指令将商存储在寄存器%eax中,将余数存储于寄存器%edx中

设置除数更常规的办法是使用cltd指令,这条指令将%eax符号扩展到%edx。

无符号除法指令使用divl指令,通常事先将%edx设置为0.

0 0
原创粉丝点击