3.5 算术和逻辑操作
下图列出了一些双字整数操作,分为四类。二元操作有两个操作数,而一元操作只有一个操作数。描述这些操作数的符号与3.4节中使用的符号完全相同,除了leal以外,每条指令都有对应的对字和对字节操作的指令。把后缀l换成w就是对字的操作,换成b就是对字节的操作。例如,addl对应有addw和addb。
这里面比较特别的指令就是leal(取地址指令),其余的指令都是比较常规的算术和逻辑运算,相比之下还比较好理解,因此LZ这里重点介绍leal指令,对于其余的指令LZ不会一一介绍,接下来我们就认识一下这个特别的leal指令吧。
leal指令
leal指令是非常神奇的一个指令,它可以取一个存储器操作数的地址,并且将其赋给目的操作数。如果用C语言当中来对应的话,它就相当于&运算。
比如对于leal 4(%edx,%edx,4),%eax这条指令来讲,我们假设%edx寄存器的值为x的话,那么这条指令的作用就是将 4 + x + 4x = 5x + 4赋给%eax寄存器。它和mov指令的区别就在于,假设是movl 4(%edx,%edx,4),%eax这个指令,它的作用是将内存地址为5x+4的内存区域的值赋给%eax寄存器,而leal指令只是将5x+4这个地址赋给目的操作数%eax而已,它并不对存储器进行引用的值的计算。
为了更好的表示这条指令的效果,LZ这里简单的画个图来表示这一过程。我们假设下图是执行指令之前,寄存器和存储器的状态。
可以看到,此时在存储器中,地址为5x+4的区域的值为1000。那么此时若是进行movl 4(%edx,%edx,4),%eax操作,很显然,%eax的值应该为1000,也就是下图。
但是如果进行leal 4(%edx,%edx,4),%eax操作的话,%eax的值就不是1000了,因为leal指令不会去取存储器当中的值,因此寄存器%eax的值应该是5x+4。
试想一下,倘若在地址为5x+4的位置存储的是变量i,那么其实这条指令就相当于&i操作,这也就是C语言当中的&取地址操作的汇编级做法。
一个示例
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;
}