算术与逻辑运算指令详解

算术与逻辑运算指令详解

前言

上一次讲解了数据传送指令,香型大家肯定对此有了一定的认识了.这些简单的汇编指令,却可以将复杂的程序井然有序的执行完毕,实在是让人惊叹.

算术与逻辑运算指令

算术逻辑运算包括很多种,各级大家应该能很快想出来,比如常见的加减乘除,与或非,左移右移等等还有一个区地址运算符,大家可能想不到,但是看完下面这一部分之后,就会觉得这个取地址运算符是个精妙的指令.

先说一下各个指令,见下图:

这里面比较特别的指令就是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, @function
arith:
    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的位置是空的吗?当然不是,地址不会跳着来,其实他存储的是返回地址,这一点在此不做过多的说明,以后遇到了再详细的说明.

小小的结一下

本章内容是认识一下一些常见的算术和逻辑运算指令.其实没有什么难度.

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-06 03:51:30

算术与逻辑运算指令详解的相关文章

购物车实现逻辑【详解】

购物车实现逻辑详解 想要实现这样的效果: 1.首先要定义其模型 2.分析页面操作 3.实现其功能函数(在fun包下新建) Cart.java /** * 购物车 * @author Administrator * */ Public class Cart { private int totalCount ; //购书数量 private float totalPrice ; //购书总价 private Map<Integer, CartItem> map= new HashMap<&g

Oracle逻辑读详解

1.物理读(physical read) 当数据块第一次读取到,就会缓存到buffer cache 中,而第二次读取和修改该数据块时就在内存buffer cache 了 以下是例子: 1.1  第一次读取: C:"Documents and Settings"Paul Yi>sqlplus "/as sysdba" SQL*Plus: Release 9.2.0.4.0 - Production on Thu Feb 28 09:32:04 2008 Copy

产品经理必备的三种逻辑思维方式详解

产品经理的逻辑思维决定了产品未来的发展规模及产品周期,作为决定产品命运的推手,这三种逻辑思考方式你必须知道. 每个人都有自己不同的思维方式,思维方式决定着看问题的层次和高度.作为靠思考为核心竞争力的产品经理,需要更强的逻辑思维能力.而这种逻辑思维的能力是需要在认识的基础上,不断实践锻炼和强化才能形成属于自己的完整的思考体系.介绍几种的逻辑思考方式供大家参考学习. 1.空.雨.伞-决策思维 产品经理作为产品的负责人,每天都会面对各个方面的决策,产品定位.项目排期.设计抉择等等.而这些决策需要产品经

Linux LVM逻辑卷详解

之前有新人问我LVM是什么鬼?我说是鸡蛋卷啊!开个玩笑啊,LVM是逻辑卷的意思. 可不能小看这个LVM的作用,它的用途重要着嘞! 下面我来科普一下LVM到底有什么作用: 要弄明白逻辑卷的作用,首先要熟悉以下的四个概念: ① PE (物理扩展) ② PV (物理卷) ③ VG (卷组,也叫PE池) ④ LV (逻辑卷) 看到这里,你肯定会说,哎呀,说的太官方了吧,根本看不懂有木有?别着急,请听我细细道来! 为什么要弄出来一个逻辑卷呢?对于正在运行的服务器,假如说磁盘空间突然不足了,这时候你应该怎么

逻辑卷详解

一. LVM作用 LVM作用主要是在实现一个可以弹性调整容量的文件系统上,而不是在新建一个性能为主的磁盘上 二. 实现流程 三.LVM的实现 1.PV的创建阶段 pvcreate: 将物理分区创建成为pv pvscan: 查询目前系统里面任何具有PV的磁盘 pvdisplay: 显示目前系统上面的PV状态 pvremove: 将PV属性删除,让该分区不具备PV属性 创建步骤: (1)先准备块设备,利用fdisk调整分区id为8e (2)然后创建pv:pvcreate [-f] /dev/sd{d

转自go_with_wind的博客Oracle逻辑读详解

原文地址:http://blog.sina.com.cn/s/blog_6ceed3280100x0om.html 1.物理读(physical read) 当数据块第一次读取到,就会缓存到buffer cache 中,而第二次读取和修改该数据块时就在内存buffer cache 了 以下是例子: 1.1  第一次读取: C:"Documents and Settings"Paul Yi>sqlplus "/as sysdba" SQL*Plus: Relea

Centos7系列(七)逻辑卷详解

博主QQ:819594300 博客地址:http://zpf666.blog.51cto.com/ 有什么疑问的朋友可以联系博主,博主会帮你们解答,谢谢支持! Centos7可以用xfs_growfs来扩大XFS文件系统,用resize2fs 来扩大ext4文件系统, 注意的是 XFS系统只能增长,不能减少!因此如果需要减少LVM的话,分区只能使用ext4了. 逻辑卷已经创建并且挂在上挂载点了,下面我们来用一个例子来做一下快照: 下面我们再来拷贝一次/boot目录下的所有数据到挂载点/data下

逻辑门电路详解1(最透彻)

逻辑门(Logic Gates)是集成电路设计的基本组件.通过晶体管或MOS管组成的简单逻辑门,可以对输入的电平(高或低)进行一些简单的逻辑运算处理,而简单的逻辑门可以组合成为更复杂的逻辑运算,是超大规模集成电路设计的基础. 最基本的逻辑门有三种,即"与"."或"."非",其符号如下图所示: 至于它们的逻辑作用这里不再列出了,免得大家说编剧我灌水,为了显得我能勉强高逼格一点,我们仔细看看逻辑门芯片中有哪些信息值得我们关注,Follow me! 如

机器学习之逻辑回归详解

目录 线性回归 方程 损失函数 求导 令导数为0,得到 逻辑回归 逻辑回归函数 逻辑回归函数如何解决二元分类过程? 逻辑回归的损失函数 梯度下降法 为什么 似然函数 推导损失函数 推导出梯度值 参考地址: https://www.zhihu.com/question/65350200 https://github.com/GreedyAIAcademy/Machine-Learning https://zhuanlan.zhihu.com/p/70587472 线性回归 方程 损失函数 求导 令