深入理解计算机系统(3.5)---特殊的算术操作指令详解

发布时间:2013-10-28 23:44:00作者:左潇龙阅读(902 )评论(0)

    引言

     

      上一章我们讨论了常见的算术与逻辑运算指令,其中比较有特点的是leal指令,本章我们再来看几个比较特殊的操作指令,这些指令可以让只有32位的寄存器存储64位的数据,是不是十分霸气侧漏呢。

     

    初识

     

      我们先来看看这些指令的大致介绍,如果各位看过上一章的话,会发现这里的指令有的会有些眼熟,但是它们的作用却截然不同。以下是书中的一张概图。

      第一个指令有些眼熟吧,它就是我们上一章当中的imul乘法指令的双字形式。不过可以看出,这里的imull指令已经完全变了味道,它将结果存入两个寄存器。接下来,我们来仔细看看这些指令。

     

    imull、mull指令

     

      这两个指令一看就是双胞胎,它们一个负责有符号全64位乘法,一个负责无符号全64位乘法。细心的猿友会发现,imull这个指令好像是负责乘法的指令,而且在之前的乘法并没有区分有符号和无符号,现在怎么又成双胞胎指令了。

      我们上一章当中出现的指令是imul指令,当它操作双字的时候,也就是imull指令。不过不同的是,它的一般形式是imull S D,这里有两个操作数,它将计算S和D的乘积并截断为双字,然后存储在D当中。由于在截断时,无符号以及有符号的二进制序列是一样的,因此此处的乘法指令并不区分有符号和无符号。

      本次我们讨论的imull指令,则与上面的普通乘法指令稍有不同,它只有一个操作数,也就是说,它的一般形式为imull S,这点在书中的表格中也能看出来,而另外一个操作数默认为%eax寄存器。最终的结果,会将高32位存入%edx寄存器,而低32位存入%eax寄存器。

      试想一下,如果我们只取%eax寄存器当中的32位结果,那其实这里计算的结果就是S*%eax,此时imull S的作用就与imull S D是一样的,只是目的操作数被固定为%eax罢了。

      接下来我们看一个简单的示例,我们去看下指令imull $0x3的结果,我们假设此时%eax寄存器的值为0x82345600。也就是我们需要计算0x3*0x82345600的值,这里LZ直接给出两者相乘的16进制表示,各位有兴趣的可以私下乘一下,为0xFFFF FFFE 869D 0200。这个结果为64位的,因此我们寄存器的前后状态如下所示。

      可以看到,%eax保存着低32位的结果,单说这32位的话,它的有符号数值为-2036530688,正是我们直接计算0x3*0x82345600的32位截断后的有符号值,显然这个结果溢出了。如果组合上高32位,则结果为-6331497984,将它加上或者取模4294967296(2的32次方)将得到我们32位的结果。这里的有符号乘法采取的是先符号扩展被乘数,然后两者相乘,将结果再截断为64位所得。

      对于mull的单操作数指令来讲,就比较简单了,它采用的是无符号乘法,因此就和我们平时的十进制乘法运算类似,只是同样的,它也会将结果的高32位存入%edx,将低32位存入%eax。

     

    cltd指令

     

      这个指令相对来说就非常简单了,它就是简单的将%eax寄存器的值符号扩展32位到%edx寄存器,也就是说,如果%eax寄存器的二进制序列的最高位为0,则cltd指令将把%edx置为32个0,相反,如果%eax寄存器的二进制序列最高位为1,则cltd指令将会自从填充%edx寄存器为32个1。

     

    idivl、divl指令

     

      这两个指令与前面的imull以及mull类似,它也将计算结果存放在两个寄存器当中,其中余数存放在%edx寄存器,商存放在%eax寄存器。如果各位理解了前面的imull以及mull,那么这里idivl和divl理解起来会非常简单。

      这里LZ举一个简单的例子,考虑指令idivl $0x3的结果,我们假设此时%eax寄存器的值为0x82345600。也就是我们需要计算0x82345600/0x3的值,这里LZ直接给出两者相除的16进制表示,各位有兴趣的也可以私下除一下,商为0xD6117200,余数为0x0。因此我们寄存器的前后状态如下所示。

      可以看到,在idivl这个指令执行的过程中,其实对被除数进行了符号扩展,类似于cltd指令,或者有时也会将%eax移动到%edx,然后对%edx进行算术右移31位的运算。这两种方式的结果是一样的,都是将%eax符号扩展32位并存储在%edx当中。

     

    文章小结

       

      本章介绍了几个特殊的算术运算指令,其实这些指令的运算规则都建立在2.X的基础之上,2.X当中所介绍的二进制算术规则,就是这些指令的执行方式规定。理解这些指令的指令方式,有助于提高我们联系程序代码与汇编代码之间的对应关系的能力,这是非常有用的。

      下一章我们将进入控制结构部分,其中用到了另外一种寄存器,名叫条件寄存器。这在之前我们是提到过这个名字的,到时我们一起来看下,条件寄存器如何控制程序的执行流程。


    版权声明:本文版权归作者(左潇龙)所有,欢迎转载。但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

    4
    精彩
    0
    感动
    0
    搞笑
    0
    开心
    0
    愤怒
    0
    无聊
    0
    灌水
    0
    惊讶
暂无评论
发表评论

站内搜索

最新评论