x86 汇编 GAS 中的划分

问题描述 投票:0回答:1

我还不太确定除法在 x86 汇编中是如何工作的(GAS AT&T 语法)。我想做的是将两个长整型相除,然后将商与除数相乘,看看新数字是否等于初始数字(n/m * m = n)。

movl %ebx, %eax
movl %ecx, %edx
idivl %edx
imull %ebx, %edx

cmp %edx, %ebx
je .equal

上面的代码是我进行除法的代码片段。

ebx
ecx
是我想要除法的两个计数器,eax寄存器用作除数是否正确?所以当我写
idivl %edx
时,我将
edx
除以
eax
,然后得到最接近 0 的整数?比如 7/2 = 3?我读到一处说商存储在
edx
寄存器中,余数存储在
ah
寄存器中,但我也被告知商存储在
eax
寄存器中,余数存储在
edx
寄存器中,这让我很困惑。

虽然这里的主要问题是:我想将

ebx
寄存器的值除以
ecx
寄存器的值,但我应该如何进行?

编辑:上面的代码产生浮点异常

assembly x86 att
1个回答
11
投票

idiv
指令在3个寄存器中接受2个参数。
第一个隐式参数是被除数,
edx:eax

中的 64 位参数 低 32 位在
eax
中,高 32 位在
edx
中。
第二个显式参数是除数,单个寄存器中的 32 位参数。
由于明显的原因,除数应该
edx
eax

结果以 eax = 商、edx = 余数形式返回。

知道这一点,正确的设置应该是:

Intel syntax                    pdp-11 syntax
--------------------------------------------------------
.intel_syntax noprefix
mov ebx, dividend
mov ecx, divisor

mov eax,ebx                     movl %ebx, %eax     
cdq                             cdq                 //edx:eax = 32 bit dividend 
idiv ecx                        idivl %ecx          //divide edx:eax by ecx
imul eax, ecx                   imull %ecx, %eax    //multiply result by dividend
cmp ebx, eax                    cmpl %eax, %ebx
je .equal                       je .equal
add eax,edx                     addl %edx, %eax     //add remainder
cmp ebx,eax                     cmpl %eax,%ebx      //should be equal now
je .equal2                      je .equal2

您应该记住,

div/idiv
执行整数除法!
结果始终是带有余数的整数(可能为零)。

它不做任何浮点运算。仅当结果太大而无法容纳 32 位或除以零时,它才会生成异常,在这种情况下,您会收到 #DE 除法错误。
您收到整数除法错误的原因是您错误地使用

edx
作为除数,并且因为您的被除数是32位,所以高32位(存储在
edx
中)始终为零,因此您有一个除以零。
切勿对被除数和除数使用相同的寄存器!
如果
edx:eax idiv ecx
不适合 32 位(即,如果
edx:eax
相对于
ecx
太大),您将得到同样的错误。

请参阅:http://www.felixcloutier.com/x86/IDIV.htmlhttp://www.felixcloutier.com/x86/DIV.html

我对 ATT 又名 PDP 语法怀有强烈的仇恨,它是无意义且破碎的。
您可以通过使用

.intel_syntax noprefix
伪指令来恢复理智并在 Gas 中使用 Intel 语法。
请参阅:我可以在 GCC 中使用 x86 汇编的 Intel 语法吗?

© www.soinside.com 2019 - 2024. All rights reserved.