C ++多线程内联asm

时间:2015-12-24 21:01:34

标签: c++ multithreading assembly

我想在一个线程中运行内联asm,但是我在某些指令上遇到了一个seg错误,如下所示:

#include <thread>

void Foo(int &x) 
{
    int temp;
    asm volatile ("movl $5, %%edx;"
                  "movl $3, %%eax;"
                  "addl %%edx, %%eax;"
                  "movl %%eax, -24(%%rbp);" // seg faults here
                  "movl -24(%%rbp), %0;"
                  : "=r" (temp) : : );
    x=temp;
}

int main() 
{
    int x;
    std::thread t1(Foo, std::ref(x));
    t1.join();
    return 0;
}

(我正在使用std::ref来传递对std::thread的引用,但必须使用temp变量,因为扩展的asm语法不能用于引用。)

我试图破坏所有涉及的寄存器,但它没有帮助。如果我没有向线程传递任何参数,它似乎可以工作:如果我破坏了%ebx寄存器(没有涉及),它也会很奇怪。我在64位Ubuntu 14.04上使用gcc 4.8.4。

在线程中执行内联asm的最佳/最安全的方法是什么?

1 个答案:

答案 0 :(得分:1)

我仍然不完全相信我明白你的目标是什么。我发现注释“但必须使用temp变量,因为扩展的asm语法不能用于引用。”有点不寻常。我希望你可以将引用传递给汇编程序模板,因为它实际上只是一个指针。由于你使用的是一个人为的例子,我将保留这一点,但不包括将数据移动到堆栈中的任意位置,并且我将添加被破坏的寄存器添加到列表中。你可能会喜欢这样的东西:

#include <thread>

void Foo(int &x) 
{
    asm volatile ("movl $5, %%edx;" // We clobber EDX
                  "movl $3, %%eax;" // We clobber EAX
                  "addl %%edx, %%eax;" // Result in EAX=3+5=8
                  "movl %%eax, %0;" // Move to variable x
                  : "=r" (x) : : "eax", "edx" );
}

int main() 
{
    int x;
    std::thread t1(Foo, std::ref(x));
    t1.join();
    return 0;
}

我已将"eax""edx"添加到clobber列表中,因为我们在汇编程序模板中销毁它们(并且它们不会显示为输入或输出约束)。您还应该注意到我不使用临时变量。汇编代码可以简化为单个指令,因为人为的例子相当于movl $8, %0;

您还可以使用x的内存地址(引用),如下所示:

void Foo(int &x) 
{
    asm volatile ("movl $5, %%edx;" // We clobber EDX
                  "movl $3, %%eax;" // We clobber EAX
                  "addl %%edx, %%eax;" // Result in EAX=3+5=8
                  "movl %%eax, %0;" // Move to variable x
                  : "=mr" (x) : : "eax", "edx" );
}

在这种情况下,我使用=mr(内存操作数或寄存器)作为输出约束。这允许我们在没有中间寄存器的情况下将值右移到内存操作数。