第5章算术和逻辑运算指令共93页文档
- 格式:pptx
- 大小:778.76 KB
- 文档页数:93
算术与逻辑运算指令具体解释算术与逻辑运算指令具体解释前⾔上⼀次解说了数据传送指令,⾹型⼤家肯定对此有了⼀定的认识了.这些简单的汇编指令,却能够将复杂的程序井然有序的运⾏完成,实在是让⼈惊叹.算术与逻辑运算指令算术逻辑运算包含⾮常多种,各级⼤家应该能⾮常快想出来,⽐⽅常见的加减乘除,与或⾮,左移右移等等另⼀个区地址运算符,⼤家可能想不到,可是看完以下这⼀部分之后,就会认为这个取地址运算符是个精妙的指令.先说⼀下各个指令,见下图:这⾥⾯⽐較特别的指令就是leal(取地址指令),其余的指令都是⽐較常规的算术和逻辑运算,相⽐之下⾮常好理解,因此在这⾥咱们重点是介绍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⽽已,它并不正确寄存器进⾏引⽤的值的计算.为了更好的表⽰这条指令的效果,咱们⽤⼀个图来简单的表⽰这⼀过程.我们如果下图是运⾏指令之前,寄存器和存储器的状态.能够看到,此时在寄存器中,地址为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语⾔其中的&取地址操作的汇编级做法.⼀个案例:因为其它的指令⾮常easy,因此咱们就不⼀⼀介绍了,咱们使⽤⼀个⼩程序来做⼀个实例,顺道看⼀下上⾯的算术与逻辑运算指令都是被怎样使⽤的.我们考虑这样⼀个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;}这⾥⾯包括了加,乘,与运算,我们使⽤GCC -O1 -S sum.c这条命令,然后使⽤cat sum.c这条命令查看,就会得到例如以下的汇编代码:.file "sum.c".text.globl arith.type arith, @functionarith:pushl %ebpmovl %esp, %ebp //以上为栈帧建⽴movl 16(%ebp), %eaxleal (%eax,%eax,2), %edxsall $4, %edxmovl 12(%ebp), %eaxaddl 8(%ebp), %eaxandl $65535, %eaximull %edx, %eax //下⾯为栈帧完毕popl %ebpret.size arith, .-arith.ident "GCC: (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3".section .note.GNU-stack,"",@progbits这⾥⾯还有leal指令,能够看到程序其中并没有取地址&操作,所以这⾥的leal指令不是⽤来取地址的,咱们使⽤⼀个图来演⽰这个程序的执⾏过程.⾸先是栈帧的建⽴过程,栈帧建⽴好以后,寄存器和存储器的状态例如以下:以上便是建⽴好的栈帧,通上⼀次⼀样,栈指针和帧指针都指向了⼀个新的位置,在帧指针偏移量为8,,12,16的地⽅存储着传递进来的參数x,y,z.接下来我们就開始分析,在汇编代码层次,是怎样完毕上述C语⾔程序其中的⼀些列动作的.⾸先是⼀个mov指令,他的作⽤⾮常easy,就是将參数z取⼊寄存器,以下是它的汇编代码以及图⽰:movl 16(%ebp),%eax上⾯的指令⽐較简单,接下来的这条指令就有点特别了,是⼀条leal指令.这⾥的leal指令不是⽤来取地址的,⽽是⽤来进⾏乘法运算的,他的⽬的是将%eax寄存器其中的值乘以3,然后发送⾄%edx寄存器.⽽採⽤的⽅式则是2*x+x的⽅式,这正是我们之前讲过的乘法优化算法,使⽤移位和加法来计算乘法.leal (%eax,%eax,2),%edx上⾯计算3z的⽬的,在接下来的这⼀条指令就看出来了.接下来的⼀条会令是sal左移操作,位数为4,左移4位事实上就相当于16,因此接下来的⼀条指令事实上就相当于将寄存器%edx当值的值乘以16,这事实上刚好是在计算48*z.从这⾥也能够看出来,在运⾏C程序的时候,并不⼀定依照程序其中的顺序去计算.下⾯是sal指令的内容与图⽰sall $4,%edx接下来的指令依旧是简单的取參数y,因此咱们就不解释了,看指令和图⽰movl 12(%ebp),%eax以下的⼀条指令是add加法指令,它是将左边操作数的值加到右边的⽬的操作数.也就是将内存地址为8(%ebp)的值加到%eax寄存器,⽽8(%ebp)这个位置存放的刚好是x,因此这⾥计算的便是x+y的值,⽽结果会存⼊%eax寄存器.以下是指令的内容和图⽰:addl 8(%ebp),%eax接下来是⼀条运算指令and,他计算的则是t1与0xFFFF(⼗进制就是65535)的与运算,t1的值为x+y,此时就存在%eax寄存器.接下来看这条指令和图⽰:andl $65535 ,%eax接下来是最后⼀个计算过程的指令imul乘法指令,它的作⽤也是将左边操作数的值乘到右边的⽬的操作数上.也就是将%edx寄存器的值乘到%eax寄存器上⾯去,⽽%edx此时的值为48*z(也就是t2),⽽%eax的值为(x+y)&0xFFFF(也就是t3),两者相乘得到t4的值,结果将存放在%eax寄存器,⽽且作为返回值返回,下⾯是指令和图⽰:imull %edx,%eax⾄此,我们整个计算过程就结束了,当中⽤到了⼀些算术与逻辑运算指令,事实上他们并没有什么难度,图例已经说得⾮常清楚了.最后则是栈帧的完毕部分,下⾯为当前帧释放后的状态:不知道打击注意到了没有,每次在%ebp偏移量为4的位置都是空着的,⽽參数都在8,12,16这种位置,难道偏移量为4的位置是空的吗?当然不是,地址不会跳着来,事实上他存储的是返回地址,这⼀点在此不做过多的说明,以后遇到了再具体的说明.⼩⼩的结⼀下本章内容是认识⼀下⼀些常见的算术和逻辑运算指令.事实上没有什么难度.。