我是gcc内联汇编的新手。 为什么这个代码输出" 1"而不是" 5"?
代码:
#include <stdio.h>
static inline int atomic_add(volatile int *mem, int add)
{
asm volatile(
"lock xadd %0, (%1);"
: "=a"(add)
: "r"(mem), "a"(add)
: "memory"
);
return add;
}
int main(void)
{
int a=1;
int b=5;
printf ( "%d\n", atomic_add(&a, b) );
return 0;
}
运行:
$ ./a.out
1 # why not 5?
许多人。 :)
答案 0 :(得分:3)
变量add
标出值为5,*mem
以1
开头。
lock xadd %0, (%1)
程序集模板由gcc编译为:
lock xadd %eax, (%edx)
GCC必须使用eax
,因为您的约束表明%0
应使用%eax
。您的约束也会将%eax
与变量add
联系起来。我相信GCC对我们任何其他操作数所需的寄存器都是免费的(在我的测试中它碰巧使用了%edx
)。
所以:
%eax
以5
开头,%edx
指向值1
xadd
指令交换两个操作数并将总和放在目标中,因此执行%eax
后1
和the memory pointed to by
%edx {{1 }} 6`
您的约束还表示应将contains
存储回变量%eax
,以便add
获得add
。这就是函数返回的内容。
答案 1 :(得分:2)
在x86中, XADD 是Exchange and Add指令。因此,在add
指令之后,保存1
参数的寄存器变为lock xadd
。 add
会返回atomic_add()
,因此您会看到1
而不是5
。
对于atomic_add()
,您可能只想使用lock add
代替lock xadd
:
#include <stdio.h>
static inline int atomic_add(volatile int *mem, int add)
{
asm volatile(
"lock add %0, (%1);"
: "=a"(add)
: "r"(mem), "a"(add)
: "memory"
);
return add;
}
int main(void)
{
int a=1;
int b=5;
printf ( "%d\n", atomic_add(&a, b) );
return 0;
}
这会像您期望的那样打印5
:
$ ./a.out
5