在上一篇博客 算术和逻辑操作 咱们介绍了如下图几种常用的算术逻辑指令,可是咱们发现没,这几种指令假如在 IA32 上只能操作32位寄存器,比方我用乘法指令IMUL得出的成果超过了32位,那就会发生成果溢出,那应该怎么办呢?

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

1、特殊的算术操作指令指令

深入理解计算机系统(3.5)------特殊的算术操作指令
  如上图,上面的几个指令支撑有符号和无符号的全64位乘积以及整数除法,可是需求注意的是,存储成果的寄存器固定死了,是一对寄存器%edx(高32位)和%eax(低32位)组成的 64 位的四字。

2、imull 和 mull 指令

  关于 imull 指令,上一章咱们在讲算术和逻辑操作指令的时候,讲过这个指令,这是一个乘法指令,指令方式是 imull S D,这儿有两个操作数,它将核算S和D的乘积并截断为双字,然后存储在D傍边。由于在截断时,无符号以及有符号的二进制序列是相同的,因而此处的乘法指令并不区别有符号和无符号。

  可是关于本章的 imull 指令,它和前面的所表明的乘法指令有所不同,这儿只有一个操作数,如上图,它的指令方式是 imull S。可是实际上它还有一个默认的操作数——寄存器%eax,这两者相乘,最终的成果是将高32位存入%edx 寄存器,低 32 位存入%eax 寄存器。

  假如咱们只取低 32 位的成果,那么这儿指令的意思和上篇博客所讲的乘法指令意思是相同的了,imull S D,只不过这儿的D是寄存器 %eax。

  这儿咱们可以看一个实例:imull $0x3,咱们假设此刻%eax寄存器的值为0x82345600。也便是咱们需求核算0x3*0x82345600的值,这儿直接给出两者相乘的16进制表明,为0xFFFF FFFE 869D 0200。这个成果为64位的,因而咱们寄存器的前后状况如下所示。

深入理解计算机系统(3.5)------特殊的算术操作指令
  可以看到,%eax保存着低32位的成果,单说这32位的话,它的有符号数值为-2036530688,正是咱们直接核算0x3*0x82345600的32位截断后的有符号值,明显这个成果溢出了。假如组合上高32位,则成果为-6331497984,将它加上或许取模4294967296(2的32次方)将得到咱们32位的成果。这儿的有符号乘法采取的是先符号扩展被乘数,然后两者相乘,将成果再截断为64位所得。

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

  所以尽管 imull 可以用于两种不同的乘法操作,可是汇编器可以经过核算操作数的数据,分辨出想用哪条指令。

3、cltd 指令

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

4、idivl、divl指令

  这两个指令分别是有符号除法和无符号除法指令,有符号除法指令 idivl 将寄存器 %edx(高32位)和 %eax(低32位)中的64位数作为被除数,而除数作为指令的操作数给出。指令将商存储在寄存器 %eax 中,将余数存储在寄存器 %edx 中。

  比方指令idivl $0x3的成果,咱们假设此刻%eax寄存器的值为0x82345600。也便是咱们需求核算0x82345600/0x3的值,这儿直接给出两者相除的16进制表明,商为0xD6117200,余数为0x0。因而咱们寄存器的前后状况如下所示。

深入理解计算机系统(3.5)------特殊的算术操作指令
  可以看到,在idivl这个指令履行的过程中,其实对被除数进行了符号扩展,类似于cltd指令,或许有时也会将%eax移动到%edx,然后对%edx进行算术右移31位的运算。这两种方式的成果是相同的,都是将%eax符号扩展32位并存储在%edx傍边。