我想在一个线程中运行内联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的最佳/最安全的方法是什么?
答案 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
(内存操作数或寄存器)作为输出约束。这允许我们在没有中间寄存器的情况下将值右移到内存操作数。