算术与逻辑运算指令详解
来源:互联网 发布:doujinmode新域名 编辑:程序博客网 时间:2024/05/01 17:06
算术与逻辑运算指令详解
前言
上一次讲解了数据传送指令,香型大家肯定对此有了一定的认识了.这些简单的汇编指令,却可以将复杂的程序井然有序的执行完毕,实在是让人惊叹.
算术与逻辑运算指令
算术逻辑运算包括很多种,各级大家应该能很快想出来,比如常见的加减乘除,与或非,左移右移等等还有一个区地址运算符,大家可能想不到,但是看完下面这一部分之后,就会觉得这个取地址运算符是个精妙的指令.
先说一下各个指令,见下图:
这里面比较特别的指令就是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语言当中的&取地址操作的汇编级做法.
一个案例:
由于其他的指令很简单,因此咱们就不一一介绍了,咱们使用一个小程序来做一个实例,顺道看一下上面的算术与逻辑运算指令都是被如何使用的.我们考虑这样一个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 %ebp movl %esp, %ebp //以上为栈帧建立 movl 16(%ebp), %eax leal (%eax,%eax,2), %edx sall $4, %edx movl 12(%ebp), %eax addl 8(%ebp), %eax andl $65535, %eax imull %edx, %eax //以下为栈帧完成 popl %ebp ret .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指令,他的作用很简单,就是将参数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的位置是空的吗?当然不是,地址不会跳着来,其实他存储的是返回地址,这一点在此不做过多的说明,以后遇到了再详细的说明.
小小的结一下
本章内容是认识一下一些常见的算术和逻辑运算指令.其实没有什么难度.
- 算术与逻辑运算指令详解
- 算术运算与逻辑运算
- 80386 算术运算指令,逻辑运算指令,移位指令 (三)
- 深入理解计算机系统(3.4)---算数与逻辑运算指令详解
- 5.c语言逻辑运算与算术运算
- SQL基础基础教程(四)算术与逻辑运算符
- 逻辑运算指令
- 逻辑运算指令
- 特殊的算术操作指令详解
- 特殊的算术操作指令详解
- 算术、关系、逻辑运算符
- Mybatis 算术逻辑运算
- 补码与算术右移指令
- SSE3指令集系列----数据加载与算术运算指令
- javascript赋值、算术、逻辑运算符
- 80X86学习笔记--逻辑运算与移位指令
- 逻辑运算与51单片机的位操作指令
- MySQL学习----MySQL 算术运算符----08MySQL 逻辑运算符与位运算符
- 操作系统原理——系统进程简析
- MySQL存储过程
- 一个解决android多渠道打包的问题插件之(兰贝壳儿)
- NullPointerException: Attempt to invoke virtual method 'android.view.ViewGroup$LayoutParam
- Java对象占内存大小分配的初步认识
- 算术与逻辑运算指令详解
- java 反射 getDeclaredMethods 和 getMehtods
- 关于安装Xtreme ToolkitPro v15.0.1出现error C2660: 'VarCmp' :错误的问题解决
- animate方法只适用于使用数值设置的css属性
- 曾经的学习笔记搬迁_140715
- 一个人的旅行
- 操作系统——第0篇
- php绘制图片失败,使用清除缓存ob_clean()可以解决。
- NBUT 1219 Time