带 masm 的寄存器 edx::eax 中的 mul 和内存分配
Posted
技术标签:
【中文标题】带 masm 的寄存器 edx::eax 中的 mul 和内存分配【英文标题】:mul and memory allocation in registers edx::eax with masm 【发布时间】:2016-12-07 16:14:02 【问题描述】:我试图了解在汇编程序中使用“mul”操作数的逻辑(我正在使用 Visual Studio Community 和 MASM)。 为什么,在“mul ebx”之后结果也在改变edx,而不仅仅是eax? “MUL 的结果存储在寄存器 AX、寄存器对 DX:AX 或寄存器对 EDX:EAX 中(取决于操作数大小),乘积的高位包含在寄存器 AH、DX 或EDX”。 那么位置是否取决于操作数的大小?在哪种情况下?
.586
.model flat,c
.stack 100h
.data
.code
doit proc
;EAX = 0062EEF0 EBX = 7EFDE000 ECX = 0029FD00 EDX = 00000000
mov eax,8;
;EAX = 00000008
mov ebx,4
;EBX = 00000004
mov edx,23498
;EDX = 00005BCA
mul ebx
;EAX = 00000020 EDX = 00000000 ???? 4*8 =20(hexa).So, there is no
;overflow;why is edx changing too?
doit endp
end
【问题讨论】:
目的地不同的原因是涉及的位数,两个8位操作数需要16位结果,所以16位寄存器AX,16位x 16位需要32位结果,所以DX:AX 的 32 位,32 位 x 32 位的结果需要 64 位,因此 EDX:EAX 中的 64 位 您可以将mul r/m8
视为在 AH:AL 中产生一对低/高输出。但是,如果您不需要结果的高半部分,您可以并且应该使用 IMUL 的 2-operand 或 3-operand-immediate 形式。
EDX 发生了变化,因为没有涉及溢出概念。这些位是结果的一部分,即使你做了零次零
【参考方案1】:
是的,正如您所说,它取决于操作数大小,这不是操作数的实际值。你总是得到双倍大小的输出,溢出与否。 mul ebx
是 32 位,因此您在 edx:eax
中获得 64 位输出,其中 edx
可能为零。
正如 Peter Cordes 所指出的,如果您知道不需要结果的上半部分,“您可以而且应该使用 IMUL 的 2 操作数或 3 操作数立即数形式”。不要被有符号所迷惑,引用指令集参考:“二操作数和三操作数形式也可以与无符号操作数一起使用,因为无论操作数是否是,乘积的下半部分都是相同的签名或未签名。”
【讨论】:
【参考方案2】:MUL
和 IMUL
指令始终生成两倍于输入宽度的输出。所以:
请注意,相关宽度始终是参数(以及隐式 A 寄存器)的宽度,而不是保存任何一个值的最小宽度。 32 位乘以零将(缓慢地)将 EDX:EAX 设置为全零。
【讨论】:
使用 16 位输入(AX 中的一个),32 位输出将在 DX:AX 而不是 EAX 中。 哦!当然。 16 位 MUL 早于 EAX,一旦引入 EAX,再改变 MUL 为时已晚。谢谢!【参考方案3】:无符号乘法(MUL
指令)总是在传递r/m32
大小的操作数时将符号扩展(嗯,零扩展,因为它是无符号的)到EDX
,无论EDX
是否包含除零以外的任何内容。
这也适用于带符号的变体IMUL
,但在这种情况下,如果结果为负,EDX
可能只包含FF
字节。
【讨论】:
术语:它不是 EDX 的符号或零扩展。它是结果的上半部分,可能是也可能不是下半部分的零扩展,具体取决于结果的大小。以上是关于带 masm 的寄存器 edx::eax 中的 mul 和内存分配的主要内容,如果未能解决你的问题,请参考以下文章
汇编程序如何处理在 2 个寄存器上分隔的值(例如 EDX:EAX)?