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

bre*_*ett 5 c assembly gcc inline-assembly

例:

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 */
}
Run Code Online (Sandbox Code Playgroud)
  • 是什么r(y)
  • 也为什么%%以前用过eax?一般单%用吗?

Nil*_*nck 6

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

首先,%char是一个特殊的char.它允许您定义寄存器和数字占位符(稍后将详细说明).不幸的是,%也被用作寄存器名称的一部分(例如%EAX),因此在gcc内联汇编程序中,如果要命名寄存器,则必须使用2%的字符.

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

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

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

你的榜样几乎毫无意义.它只是将值X加载到寄存器中并将该寄存器分配给EAX.之后EAX被存储到另一个寄存器中,然后该寄存器将成为您的y变量.所以它只是一个简单的任务:

y = x;

最后一件事:如果您之前使用过Intel风格的汇编程序:您必须向后阅读这些参数.对于所有指令,源操作数是指令本身之后的操作数,目标​​操作数是逗号右侧的操作数.与英特尔语法相比,这恰恰相反.