【问题标题】:Division in x86 Assembly GASx86 汇编 GAS 中的除法
【发布时间】:2016-09-23 10:52:36
【问题描述】:

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

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

cmp %edx, %ebx
je .equal

上面的代码是我做除法的sn-p。 ebx 和 ecx 是我要除的两个计数器,将 eax 寄存器用作除数是否正确?所以当我写 idivl %edx 时,我将 edx 与 eax 相除,我得到最接近 0 的整数?比如 7/2 = 3?我读过一个地方,商存储在 edx 寄存器中,余数存储在 ah 寄存器中,但我也被告知商存储在 eax 寄存器中,余数存储在 edx 寄存器中,这让我感到困惑。

虽然这里的主要问题是:我想将 ebx 寄存器的值除以 ecx 寄存器的值,我应该如何进行?

谢谢!

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

【问题讨论】:

  • 如果你想查看n/m*m == n 那么n % m == 0 就足够了
  • 当然,我没想过,谢谢@LưuVĩnhPhúc 但是,我在哪里可以找到余数/模数?
  • “我在哪里可以找到余数/模数?” 与任何其他 x86 指令相同的位置:在 英特尔® 64 和 IA-32 架构软件开发人员手册中
  • 让我为您搜索一下 - 好的,x86.renejeschke.de/html/file_module_x86_id_137.html - 被除数在 %edx:%eax(一个 64 位值)中,除数是操作数(使用 %edx 似乎是个坏主意,因为它构成股息的一部分),商转到%eax,余数转到%edx
  • 顺便说一句“上面的代码产生了一个浮点异常”我对此表示怀疑,该代码中没有浮点指令。

标签: assembly x86 att


【解决方案1】:

idiv 指令在 3 个寄存器中接受 2 个参数。
第一个 隐式 参数是被除数,edx:eax 中的 64 位参数
低32位在eax,高32位在edx
第二个 显式 参数是除数,是单个寄存器中的 32 位参数。
由于显而易见的原因,除数应该edxeax
结果以 eax = Quotient, edx = Remainder 的形式返回。

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

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

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

【讨论】:

  • POSIX requires that integer divide errors raise SIGFPE,如果他们提出任何异常。这就是 OP 看到“浮点异常”的原因。
  • xor edx,edx 在 IDIV 之前通常是一个错误。有符号除法的正确设置是使用 CDQ 将 EAX 符号扩展为 EDX:EAX。我想如果你的股息是无符号的,但你的除数是有符号的,你可以将 EDX 归零。
猜你喜欢
  • 2016-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-14
相关资源
最近更新 更多