帮助理解 x86 内联汇编中的 DIV 指令

Posted

技术标签:

【中文标题】帮助理解 x86 内联汇编中的 DIV 指令【英文标题】:Help understanding DIV instruction in x86 inline assembly 【发布时间】:2010-12-27 19:03:28 【问题描述】:

在阅读 GNU 项目中的一些源代码时,我遇到了以下内联汇编:

__asm__ (
  "divq %4"
  : "=a" (q), "=d" (r)
  : "0" (n0), "1" (n1), "rm" (d)
);

这里的变量qrn0n1d是64位整数。我知道足够多的程序集来了解它的作用,但有些细节我不确定。

我的理解:

我们将 RAX 寄存器的内容除以 d,将商放入 q,将余数放入 r

我不明白的地方

    为什么有 三个 输入 这里?我们只需要输入一个 被除数和除数,那有什么用 可以有 3 个输入吗? 我不知道哪个输入是股息。更一般地说,我实际上什么也没看到 被加载到 RAX 寄存器中, 那么它是如何知道除以什么的呢?

【问题讨论】:

+1 个格式正确的问题。我喜欢“我明白的”和“我不明白的”部分。 【参考方案1】:

在输入操作数规范中:

: "0" (n0), "1" (n1), "rm" (d)

由于输出规范,寄存器“0”和“1”被强制为raxrdx

: "=a" (q), "=d" (r)

div 指令族需要RDX:RAX 中的分子。除数可以在通用寄存器(不以其他方式使用 - 即,不是RAXRDX)或内存中,由“rm”约束指定。寄存器RDXRAX 和除数操作数构成了 3 个输入。

所以这将最终执行除法:n1:n0 / d 其中n1:n0 是加载到rdx:rax 中的数量。

【讨论】:

我是否正确理解这可用于将 128 位整数除以 64 位整数?我知道这对于 32 位寄存器版本是可能的,但从没想过它也适用于 64 位版本。 @Jens:没错。但请记住(如较小的操作数除法运算),如果商最终对于rax 目标寄存器来说太大,您将得到除法异常。 测试这种情况的快速方法是确保rdx小于除数,在这种情况下除法是安全的。【参考方案2】:

当您正确观察到div 系列在固定寄存器adraxrdx 上工作divqa 寄存器从n0 获取输入,n0 别名为第 0 个寄存器,即an1 是一个别名为d 的虚拟输入,可能只是为了确保该寄存器不用于其他目的。

【讨论】:

以上是关于帮助理解 x86 内联汇编中的 DIV 指令的主要内容,如果未能解决你的问题,请参考以下文章

x86 - 使用内联汇编设置位

MSVC 内联汇编中的“拒绝”是啥意思

内联汇编

Solidity 中编写内联汇编(assembly)

优化系列汇编优化技术:x86架构内联汇编及demo

在 GCC 内联汇编中检索 ZF