内联汇编:注册引用约定

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.html asm ("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 请考虑接受答案。在 ***,我们不会说谢谢。我们接受并投票赞成答案。

以上是关于内联汇编:注册引用约定的主要内容,如果未能解决你的问题,请参考以下文章

Clang:通过内联汇编获取函数的参数

在 gcc 中使用内联汇编程序调用方法

VC内联汇编,引用程序中的变量

GCC 内联汇编到 IAR 内联汇编

GCC 扩展内联汇编简介

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