内联汇编约束修饰符=和+

cpp*_*ame 2 c c++ assembly gcc inline-assembly

我写了一个包含内联汇编代码的简单程序.我的代码只是添加了变量a和b,并在b中返回结果.

令我困惑的是为什么下面的代码生成了这个指令movl 28(%esp),%ecx.

我没有完全承担修饰符+和=在输入和输出列表中扮演的角色.如果你能对此有所了解,我们将不胜感激.

#include <cstdio>

int main( int argc , char ** argv )
{
    int a = 2, b = 7;

    __asm__
    (
     "addl %1,%0;"      
    :"+r"(b)           
    :"r"(a), "r"(b)     
    );

    printf("b = %d\n",b);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)
    movl    $2, 24(%esp)
    movl    $7, 28(%esp)

    movl    24(%esp), %edx
    movl    28(%esp), %ecx
    movl    28(%esp), %eax

    addl %edx,%eax

    movl    %eax, 28(%esp)
Run Code Online (Sandbox Code Playgroud)

我接下来要展示的是错误的.但这是为了让我更好地了解海湾合作委员会的情况.

好的,现在我从+ r变为= r.这是GCC生成的汇编代码.

#include <cstdio>

int main( int argc , char ** argv )
{
    int a = 2, b = 7;

    __asm__
    (
     "addl %1,%0;"      
    :"=r"(b)           
    :"r"(a), "r"(b)     
    );

    printf("b = %d\n",b);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)
    movl    $2, 24(%esp)
    movl    $7, 28(%esp)
    movl    24(%esp), %eax
    movl    28(%esp), %edx

    addl %eax,%eax;

    movl    %eax, 28(%esp)
Run Code Online (Sandbox Code Playgroud)

现在输出是4,这是错误的.我的问题是为什么用"= r"GCC决定重用b的寄存器eax,如本指令addl%eax,%eax所示;

Mik*_*our 5

让我感到困惑的是为什么下面的代码生成了这条指令 movl 28(%esp), %ecx

因为你已经列b在两个独立的输入寄存器中; 所述+第一部分是指所述组件读取和修改的寄存器.所以它被加载到两个寄存器中,即使程序集不使用第二个寄存器.

组装应该只是:

"addl %1,%0;" : "+r"(b) : "r"(a)
Run Code Online (Sandbox Code Playgroud)

我没有完全承担修饰符+和=在输入和输出列表中扮演的角色.

+表示读取和写入寄存器,因此它必须在汇编开始之前具有变量的值.=意味着它只是写入,并且可以在程序集之前具有任何值.

有关完整详细信息,请参阅文档

我的问题是为什么用"= r"GCC决定使用b的寄存器eax,如本指令addl%eax,%eax所示;

因为现在你的约束是错误的.您告诉编译器您只写入addl指令(%0)的第二个操作数,因此它假定它可以使用相同的寄存器作为其中一个输入.实际上,操作数也是一个输入addl.然后你仍然告诉它你需要b在一个单独的寄存器中的第二个副本,该程序集不使用.

正如我上面所说的,使用"+r"(b)在所述第一(输出)列表,以指示那%0b,用于输入和输出,并且"r"(a)在第二(输入)列表中,表示%1a与只用于输入.不要放入第三个寄存器,因为%2组件中没有.