曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 5351|回复: 1
打印 上一主题 下一主题

乘法及其指令

[复制链接]

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
跳转到指定楼层
楼主
发表于 2010-1-24 19:50:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
无符号乘法指令 MUL
指令格式为:
mul source
source 可以是 8 位、16位或者 32 位寄存器或内存值。这里,目标操作数隐含在 EAX 寄存器的某种形式中。这某种形式是根据源操作数的长度,另一个操作数会存放在AL,AX 或者是 EAX 中。

当源操作数是 8 位时,则目标操作数为 AX 寄存器,因为结果是 16 。

注意,当源操作数是 16 位时,EAX 寄存器尽管是 32 位,但它不会用来保存 32 位的结果。这是因为,Intel 为了向下兼容老式的处理器,而使用了 DX:AX 寄存器来保存 32 位乘法结果。结果的高位字存储在 DX 寄存器中,低位字存储在 AX 寄存器中。

对于 32 位源操作数,目标位置使用 64 位 EDX:EAX 寄存器对来保存结果,高位双字存储在 EDX 寄存器中,低位双字在 EAX 寄存器中。

上面 3 种情况如下表总结:
源操作数长度
目标操作数
目标位置
8位
AL
AX
16位
AX
DX:AX
32位
EAX
EDX:EAX

测试代码
.section .data
[pre]data1:
    .int 315814
data2:
    .int 165432
result:
    .quad 0
output:
    .asciz "The result is %qd\n"

.section .text
.global _start
_start:
    nop
    movl data1, %eax
    mull data2
    movl %eax, result
    movl %edx, result+4
    pushl %edx
    pushl %eax
    pushl $output
    call printf
    add $12, %esp
    pushl $0
    call exit
运行输出
$ ./mul
The result is 52245741648
既然把结果值存到了 result 处,那么也可以把 result 里存储的值压入栈中,以供打印,修改上面程序中的压入寄存器部分为:
pushl result+4
pushl result
注意,result 前面没有 $ 符号,这表示取值,如果有则表示 result 标号所在的地址。

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
沙发
 楼主| 发表于 2010-1-24 23:49:12 | 只看该作者

带符号乘法指令 IMUL

一、使用 IMUL 进行带符号整数乘法
MUL 指令只能用于无符号整数,而 IMUL 指令可以用于带符号和无符号整数,但是必须小心结果不使用目标的最高有效位。

IMUL 指令有 3 种格式:
      imul source
source 操作数可以是 8 位、16位或者 32 位寄存器或内存中的值,它与位于 AL、AX 或者 EAX 寄存器(取决于源操作数的长度)中的隐含操作数相乘。然后,结果放到 AX 寄存器、DX:AX 寄存器对或者是 EDX:EAX 寄存器对中。

IMUL 指令的第 2 种格式允许指定 EAX 寄存器之外的目标操作数:
      imul source, destination
其中,source 可以是 16 位或者 32 位寄存器或是内存中的值,destination 必须是 16 位或者是 32 位通用寄存器。这种格式允许指定把乘法操作的结果存放到哪个位置 (而不是强制使用 AX 和 DX 寄存器)。这种格式的缺陷是,乘法操作的结果被限制为单一目标寄存器的长度(非 64 位结果)。使用这种格式时必须非常小心,不要溢出目标寄存器!

IMUL 指令的第 3 种格式允许指定 3 个操作数:
      imul multiplier, source, destination
其中,multiplier 是一个立即数,source 是 16 位或者 32 位寄存器或是内存中的值,destination 必须是通用寄存器。这种格式允许执行一个值 (source) 和一个带符号整数 (multiplier) 的快速乘法操作,最后结果存在通用寄存器(destination)中。

和 MUL 指令一样,使用 IMUL 指令,要记住在其结尾添加长度字符(b, w, l),以便指定源和目标操作数的长度。

测试程序
.section .data
value1:
    .int 10
value2:
    .int -35
value3:
    .int 400

.section .text
.global _start
_start:
    nop
    movl value1, %ebx
    movl value2, %ecx
    imull %ebx, %ecx
    movl value3, %edx
    imull $2, %edx, %eax
    movl $1, %eax
    movl $0, %ebx
    int $0x80
在调试器里查看运算后的相关值:
(gdb) info reg
eax            0x320    800
ecx            0xfffffea2    -350
edx            0x190    400
ebx            0xa    10
在上面的 imull $2, %edx, %eax 里,如果把立即数改成一个很大的数,假设产生溢出,那么想成的结果就会不断的减去 n 个 0x100000000 ,直至剩下不至于使 32 位寄存器溢出的值。

检查溢出
当使用带符号整数和 IMUL 指令时,总要记住检查结果中的溢出,这可以用 JO 指令来检测(另一种方式是检查进位标志)。

测试程序:
.section .text
.global _start
_start:
    nop
    movw $680, %ax
    movw $100, %cx
    imulw %cx
    jo over
    movl $1, %eax
    movl $0, %ebx
    int $0x80

over:
    movl $1, %eax
    movl $1, %ebx
    int $0x80
运行与输出:
$ ./imultest
$ echo $?
1
从输出可以看到,结果发生了溢出。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-5-14 07:15 , Processed in 0.059754 second(s), 21 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表