内联汇编:注册引用约定
Posted
技术标签:
【中文标题】内联汇编:注册引用约定【英文标题】:Inline assembly : register referencing conventions 【发布时间】:2013-12-11 04:43:58 【问题描述】:在网上找到的 gcc 内联汇编示例中,我看到寄存器名称有时用一个 %
引用,有时用两个(即%%
)引用。何时使用尚不清楚
单个%
以及何时使用%%
。
例如请看下面的例子。
/* Do b = a */
int a=10, b;
asm ("movl %1, %%eax;\n"
"movl %%eax, %0;"
: "=r" (b) /* output */
: "r" (a) /* input */
: "%eax" /* clobbered register */
);
这个使用%%
前缀作为EAX
寄存器的例子在我的x86机器上编译得很好(Linux RedHat 5.6(Tikanga 2.6.18-238.5.1.el5 x86_64,内核2.6.18,gcc 4.7.2)。但是下面的单行代码
asm ("movl %%ecx, %%eax");
产生以下错误。
a.c: Assembler messages:
a.c:14: Error: bad register name `%%ecx'
有人可以说明何时使用%
以及何时使用%%
吗?
谢谢。
【问题讨论】:
你绝对应该阅读ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.htmlasm ("movl %ecx, %eax");
是基本 asm 的正确语法,但不能安全地在任何地方使用;这会在不告诉编译器的情况下破坏 EAX。 gcc.gnu.org/wiki/ConvertBasicAsmToExtended
【参考方案1】:
在asm
的主体内(即实际代码所在的部分),您使用%1
、%2
等来引用inline-asm 块的参数。为此,inline-asm 将 %
视为特殊字符。
碰巧x86 的GNU 汇编器语法也 使用%
作为x86 寄存器名称的前缀(%eax
、%ebx
等)。但是,因为 inline-asm 为 %
赋予了不同的含义,所以您必须在该块中将 %
加倍才能转义它。这就是为什么你会看到movl %1, %%eax
:第一个%1
扩展为一个参数,%%eax
前面的%%
被替换为单个%
,导致编译器在最终汇编输出中出现%eax
.
在代码块之后的其他字符串中,%
不再具有此特殊含义。这就是为什么在clobber列表中,例如,你只需要说%eax
。
在您的第二个示例中,内联汇编程序没有参数。没有 %1
... 替换说明符,因此您不需要将 %
加倍。
一清二楚?
【讨论】:
感谢 Joe Z、Rob Starling 和 elyashiv。我确实阅读了 Rob Starling 提到的页面,但它并没有解释这个 % Vs %% 差异以及 Joe Z 的解释。阅读 Joe Z 的解释后,现在很清楚了。再次感谢乔 Z。 @user3017124 请考虑接受答案。在 ***,我们不会说谢谢。我们接受并投票赞成答案。以上是关于内联汇编:注册引用约定的主要内容,如果未能解决你的问题,请参考以下文章