2010-08-28 74 views
5

例子:什么是GCC内联汇编语言中的r()和double%%%?

int main(void) 
{ 
    int x = 10, y; 

    asm ("movl %1, %%eax;" 
     "movl %%eax, %0;" 
     :"=r"(y) /* y is output operand */ 
     :"r"(x)  /* x is input operand */ 
     :"%eax"); /* %eax is clobbered register */ 
} 
  • 是什么r(y)
  • 也为什么%%之前使用eax?一般情况下单人使用%对不对?
+0

另外我没有得到= r(y)和r(x)?还有什么是一个破碎的寄存器? – brett 2010-08-28 02:12:52

+0

双百分号subquestion:http://stackoverflow.com/questions/14745631/what-does-a-double-percent-sign-do-in-gcc-inline-assembly – 2015-07-29 20:34:47

+0

谨防基本VS扩展ASM:HTTP:// stackoverflow.com/a/31711138/895245 – 2015-07-29 21:08:32

回答

4

好的,这是gcc内联汇编程序,它非常强大但很难理解。

首先,%char是一个特殊的字符。它可以让你定义寄存器和数字占位符(稍后在此)。不幸的是,%也被用作寄存器名称的一部分(例如%EAX),所以在gcc内联汇编器中,如果要命名寄存器,则必须使用两个百分比字符。

%0,%1和%2(例如..)是占位符输入和输出操作数。这些在汇编程序字符串后面的列表中定义。 在你的例子中,%0成为y的占位符,%1成为x的占位符。编译器将确保变量在asm-code被执行前保存在输入操作数的寄存器中,并确保输出操作数将被写入输出操作数列表中指定的变量。

现在您应该了解r(y)是什么:它是一个输入操作数,它为变量y保留一个寄存器并将其分配给占位符%1(因为它是列在内联汇编器之后的第二个操作数串)。 有很多其他的占位符类型。 m让你指定一个内存位置,如果我没有弄错我可以用于数字常量。你会发现它们都列在gcc文档中。

然后是clobber列表。这份清单很重要!它列出了在您的汇编代码中被修改的所有寄存器,标志,存储位置等(例如您的示例中的EAX)。如果你得到这个错误,优化器将而不是知道什么已被修改,并且很可能你最终得到的代码不起作用。

你的例子几乎毫无意义。它只是将值X加载到寄存器中,并将该寄存器分配给EAX。之后,EAX被存储到另一个寄存器中,随后将成为你的变量。所以它只是一个简单的作业:

y = x;

一个最后一件事:如果你之前已经与英特尔式的汇编工作:你要倒读的论点。对于所有指令,源操作数是指令本身后面的操作数,目标​​操作数是逗号右侧的操作数。与英特尔语法相比,这恰恰相反。

0

我无法回答所有这些,但是一个破坏性寄存器是一个会在计算中以某种方式被用来破坏其当前值的方法。因此,如果调用者想要稍后使用当前值,则需要以某种方式保存它。

asm这样的指令中,当你编写程序集时,你会发现哪些寄存器将被它破坏;然后你告诉编译器(如你的例子所示),并且编译器会做必要的事情来保留该寄存器的当前值。编译器非常了解寄存器和其他地方的值如何用于以后的计算,但通常无法分析嵌入式汇编。所以你自己做分析,编译器使用clobbering信息来安全地将程序集合到其优化选项中。

0

尝试this tutorial。它涵盖了你所要求的一切:例如,尝试section 6 - 它很好地解释了约束条件,以及“=”符号的用途。甚至涵盖了破损寄存器的概念(5.3节)。

+0

此问题中的代码示例看起来是该教程第5部分的第三个示例... :-) – 2010-08-28 02:36:45

+0

@Laurence如果OP实际上使用该教程,则此问题仅仅是表示他/她还没有阅读整个教程,因为在教程中回答了每个问题。 – 2010-08-28 03:48:51

1

带“r”或“= r”的行是操作数约束。 “=”表示输出操作数。本质上,这样的:

:"=r"(y) 
:"r"(x) 

意味着%0(即:第一个操作数)对应于y和为输出,和1%(第二操作数)对应于x。

单个%通常用于AT & T语法汇编,但对于内联汇编,单个%用于操作数引用(例如:%0,%1),而双精度%用于文字寄存器引用。想想看,如果你需要输出中的文字%,你必须使用printf格式的double%。

破坏寄存器是一个寄存器,其值将被汇编代码修改。从代码中可以看到,eax是写入的。你需要告诉gcc关于这个,以便它知道编译后的代码在它将要调用这个程序集时不能保留它在eax中需要的任何东西。