首页
学习
活动
专区
圈层
工具
发布
23 篇文章
1
深入理解计算机系统(4.1)------Y86指令集体系结构
2
深入理解计算机系统(3.8)------数组分配和访问
3
深入理解计算机系统(3.7)------过程(函数的调用原理)
4
深入理解计算机系统(3.6)------汇编的流程控制
5
深入理解计算机系统(2.7)------浮点数舍入以及运算
6
深入理解计算机系统(3.2)------程序编码以及数据格式
7
深入理解计算机系统(2.6)------整数的运算
8
深入理解计算机系统(2.1)------信息的存储和表示
9
深入理解计算机系统(1.1)------Hello World 是如何运行的
10
深入理解计算机系统(1.3)------操作系统的抽象概念
11
深入理解计算机系统(序章)------谈程序员为什么要懂底层计算机结构
12
深入理解计算机系统(1.2)------存储设备
13
深入理解计算机系统(2.2)------进制间的转换原理
14
深入理解计算机系统(2.7)------二进制小数和IEEE浮点标准
15
深入理解计算机系统(2.3)------布尔代数以及C语言运算符
16
深入理解计算机系统(2.5)------C语言中的有符号数和无符号数以及扩展和截断数字
17
深入理解计算机系统(3.1)------汇编语言和机器语言
18
深入理解计算机系统(2.4)------整数的表示(无符号编码和补码编码)
19
深入理解计算机系统(3.5)------特殊的算术操作指令
20
深入理解计算机系统(3.3)------操作数指示符和数据传送指令
21
深入理解计算机系统(3.4)------算术和逻辑操作
22
深入理解计算机系统(4.2)------逻辑设计和硬件控制语言HCL
23
深入理解计算机系统(5.1)------优化程序性能

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

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

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

  如上图,上面的几个指令支持有符号和无符号的全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位的,因此我们寄存器的前后状态如下所示。

  本实例引用:http://www.cnblogs.com/zuoxiaolong/p/computer17.html

  可以看到,%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。因此我们寄存器的前后状态如下所示。

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

下一篇
举报
领券