【发布时间】:2016-02-02 15:49:08
【问题描述】:
我有这个 32 位代码:
unsigned long long load(volatile unsigned long long *target) {
unsigned long long result;
__asm__ __volatile__
(
"movl %%ecx, %%edx\n\t"
"movl %%ebx, %%eax\n\t"
"lock cmpxchg8b %0\n\t"
"movl %%edx, 4%1\n\t"
"movl %%eax, %1\n\t"
: "+m" (*target)
: "o" (result)
: "eax", "ebx", "ecx", "edx", "memory", "cc"
);
return result;
}
当它用 gcc 5.3 版编译时,代码的尾部会产生这个汇编代码(为了清楚起见,稍微编辑一下):
lock cmpxchg8b (%esi)
movl %edx, 48(%esp)
movl %eax, 8(%esp)
movl 8(%esp), %eax
movl 12(%esp), %edx
调用cmpxchg8b 的结果在EDX:EAX 中。生成的代码将 EDX 存储在 48(%esp),从 12(%esp) 重新加载 EDX,所以返回值是废话。其他版本的 gcc 可以做到这一点。
有人知道这个错误的解决方法吗?还是我误解了 gcc 的内联 asm 的一些基本内容(这不会让我感到惊讶)?
【问题讨论】:
-
4%1?这到底是什么意思?你想要4+%1吗?请注意,o约束意味着可以在地址中添加一个小整数,结果也是有效的内存地址。 -
当然,内联汇编的使用不是很好,最好将输出留在
edx和eax中并让编译器处理它。 gcc 也有 atomic builtins,所以你可能根本不需要内联 asm。 -
@HubertApplebaum - gcc -S test.cpp,使用 gcc 5.3。
-
除了 Jester 回答中的优点外,%1 是一个输入。如果你正在写它,它需要是一个输出或输入/输出。
-
@Jester - 谢谢,将
4%1更改为4+%1修复了其他地方的一些问题,尽管不是这个特定的问题。
标签: gcc assembly x86 inline-assembly