如何在汇编中实现取模运算符

8
我正在学习汇编语言中的除法。根据我所学的书籍,idiv操作的结果会放在eax寄存器中,余数会放在edx寄存器中。
书中的一个练习是在汇编中实现number = result % divisor
我本以为这与普通的除法操作等价,只不过edx是结果。然而,这并没有起作用,edx返回了看似垃圾的值。
为什么?如何在汇编中实现上述伪代码?

4
我将编写一个小的 C 函数,并查看所生成的汇编代码(例如,使用 gcc -O -fverbose-asm -S tiny.c 命令)。 - Basile Starynkevitch
2
你的问题类似于https://dev59.com/fmsz5IYBdhLWcg3wQFe2#8022107。如果你遇到了具体的问题,请展示你的实际代码(很可能是因为你没有清除rdx:rax、edx:eax或dx:ax的上部分)。 - user786653
很难在没有看到代码的情况下猜测,但一个常见的失误是在 idiv 之前忘记将 edx 清零。 - Jerry Coffin
1个回答

20

整数模运算可以通过两种方式实现:

首先是使用 DIVIDIV,余数将被放入 EDX,但您需要先将 EDX 清零,或者引用英特尔的话:

Operand Size -----------| Dividend | Divisor | Quotient | Remainder
Quadword/doubleword     | EDX:EAX  |  r/m32  |   EAX    |   EDX. 

例如:

eax = eax % 9

当无符号变成:

XOR EDX,EDX ;clear the destinations for outputs. this stops the garbage remainder  
MOV ECX,9
DIV ECX
MOV EAX,EDX

签名后,它是:

MOV ECX,9
CDQ ;this will clear EDX due to the sign extension
IDIV ECX
MOV EAX,EDX

第二种方法是在对二的幂取模时使用的一种优化,此时您需要通过比二的幂少一的数字进行AND运算,例如:eax = eax % 8变成AND EAX,7


既然idiv是有符号版本,那么你不应该将CDQ转换为edx吗? - harold
我试图删除我的问题,但你已经回答了。我只想指出,在我添加代码示例后,它可能会有很大的变化。 - Sonny Ordell
谁他妈的给这个投票点了个踩,为什么?你要么不懂x86汇编,要么就是毫无理由地在踩它... - Necrolis
2
@Necrolis 这对于有符号数不起作用。我得到了负数结果,这应该是不正确的。 - iordanis
@μακακας 这不应该是正确的,但它确实是。硬件不能执行适当的有符号除法;它执行截断除法,这可能会产生负余数。 - Michael Morris
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接