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 位参数。
出于显而易见的原因,除数应该 而不是 是 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.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?
我不太确定除法在 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 位参数。
出于显而易见的原因,除数应该 而不是 是 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.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?