GCC 扩展 Asm - 了解 clobbers 和暂存寄存器的使用

Posted

技术标签:

【中文标题】GCC 扩展 Asm - 了解 clobbers 和暂存寄存器的使用【英文标题】:GCC extended Asm - Understanding clobbers and scratch registers usage 【发布时间】:2018-03-02 10:31:06 【问题描述】:

从关于 Extended ASM - Clobbers and Scratch Registers 的 GCC 文档中,我发现很难理解以下解释和示例:

这是一个虚构的平方和指令,它需要两个 指向内存中浮点值的指针并产生一个浮点数 点寄存器输出。请注意,x 和 y 在 asm 参数,一次指定访问的内存,一次指定一个 asm 使用的基址寄存器。

好的,第一部分明白了,现在继续:

您通常不会浪费 通过这样做注册,因为 GCC 可以为两者使用相同的寄存器 目的。但是,将 %1 和 %3 同时用于 x in 这个 asm 并期望它们是相同的。事实上,%3 很可能不是 登记。它可能是对对象的符号内存引用 由 x 指向。

失去了我。

例子:

asm ("sumsq %0, %1, %2"
     : "+f" (result)
     : "r" (x), "r" (y), "m" (*x), "m" (*y));

这个例子和句子的第二部分告诉我们什么?与其他代码相比,此代码的附加值是多少?这段代码是否会导致更有效的内存刷新(如本章前面所述)?

【问题讨论】:

这个例子我也看不懂。 【参考方案1】:

与其他代码相比,此代码的附加值是什么?

哪个“另一个”?在我看来,如果你有这种指令,你几乎必须使用这段代码(唯一的选择是通用的memoryclobber)。

情况是,您需要将寄存器传递给指令,但实际操作数在内存中。因此,您需要确保两件独立的事情,即:

    您的指令获取寄存器中的操作数。这就是 r 约束的作用。 编译器知道您的asm 块读取内存,因此*x*y 的值必须在块之前刷新。这就是 m 约束的用途。

您不能使用%3 代替%1,因为m 约束使用内存引用语法。例如。而%1 可能类似于%r0%eax%3 可能是(%r0)(%eax),甚至只是some_symbol。不幸的是,您的假设指令不接受这些类型的操作数。

【讨论】:

值得一提的是,这种事情的主要用例是当您想自己构建寻址模式时,尽管在这种情况下,您需要告诉您引用的编译器而不是 *x整个数组,而不仅仅是第一个元素。请参阅***.com/questions/1956379/att-asm-inline-c-problem/… 进行讨论。 顺便说一句,如果您告诉编译器您将修改指针寄存器并使用早期破坏器,它通常确实会为虚拟内存操作数使用另一个寄存器。 ("+&r"(buffer), "m" (*(const char (*)[]) *buffer).) 如果你对编译器撒谎并忽略了 early-clobber,你可以避免这种情况,但是如果任何其他操作数与该指针具有相同的值,那么你就有一个潜在的错误。

以上是关于GCC 扩展 Asm - 了解 clobbers 和暂存寄存器的使用的主要内容,如果未能解决你的问题,请参考以下文章

GCC 内联汇编错误:变量 '%al' 的 asm 说明符与 asm clobber 列表冲突

asm、asm volatile 和 clobbering memory 的区别

x86 ASM - cpuid 是不是设置标志?

扩展 GCC asm 中多个输入和输出操作数的正确用法是啥?

如何在没有扩展内联 asm 的情况下在 gcc 内联汇编中声明和初始化局部变量?

GCC 扩展内联汇编简介