x86 汇编 GAS 中的划分

Division in x86 Assembly GAS

我不太确定除法在 x86 汇编中是如何工作的(GAS AT&T 语法)。我想做的是将两个 long 相除,然后将商乘以除数以查看新数字是否等于初始数字 (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寄存器的值,我应该如何进行?

谢谢!

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

idiv 指令在 3 个寄存器中接收 2 个参数。
第一个隐式参数是被除数,edx:eax
中的一个64位参数 低32位在eax,高32位在edx.
第二个 explicit 参数是除数,单个寄存器中的 32 位参数。
出于显而易见的原因,除数应该 而不是 edxeax.
结果在 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.html and http://www.felixcloutier.com/x86/DIV.html

I have a burning hate 用于 ATT aka PDP 语法,它是无意义且损坏的。
您可以通过使用 .intel_syntax noprefix 伪指令恢复理智并在 Gas 中使用 Intel 语法。
参见:Can I use Intel syntax of x86 assembly with GCC?