Error : Invalid Character '(' in mnemonic
Error : Invalid Character '(' in mnemonic
您好,我正在尝试使用 gcc 7.5 版本在 Linux 上编译以下汇编代码,但不知何故出现错误
Error : Invalid Character '(' in mnemonic
bool InterlockedCompareAndStore128(int *dest,int *newVal,int *oldVal)
{
asm(
"push %rbx\n"
"push %rdi\n"
"mov %rcx, %rdi\n" // ptr to dest -> RDI
"mov 8(%rdx), %rcx\n" // newVal -> RCX:RBX
"mov (%rdx), %rbx\n"
"mov 8(%r8), %rdx\n" // oldVal -> RDX:RAX
"mov (%r8), %rax\n"
"lock (%rdi), cmpxchg16b\n"
"mov [=10=], %rax\n"
"jnz exit\n"
"inc1 %rax\n"
"exit:;\n"
"pop %rdi\n"
"pop %rbx\n"
);
}
任何人都可以建议如何解决这个问题。检查了汇编代码的许多在线链接和教程,但无法解决确切的问题。
提前感谢您的帮助。
在Windows中我可以看到上述函数的实现是:
function InterlockedCompareExchange128;
asm
.PUSHNV RBX
MOV R10,RCX
MOV RBX,R8
MOV RCX,RDX
MOV RDX,[R9+8]
MOV RAX,[R9]
LOCK CMPXCHG16B [R10]
MOV [R9+8],RDX
MOV [R9],RAX
SETZ AL
MOVZX EAX, AL
end;
对于 PUSHNV ,我在 Linux 上找不到与此相关的任何内容。所以,基本上我试图在 Linux.
上用 c++ 实现相同的功能
此代码存在许多问题,我不认为告诉您如何解决具体问题对您有任何帮助。
但简短的回答是
"lock (%rdi), cmpxchg16b\n"
应该是
"lock cmpxchg16b (%rdi)\n"
Tada,现在可以编译了。好吧,如果 inc1
是一个真正的指令。
但是我不禁注意到这里的指针是int *
,也就是4个字节,而不是16个。而且这个函数没有被声明为naked
。使用 Extended asm 将使您不必手动推动所有这些寄存器,从而使这段代码比需要的慢很多。
但最重要的是,您应该真正使用 builtins,例如 __atomic_compare_exchange
,因为内联 asm 容易出错,不可移植,而且 真的 很难维护。
这里的问题是关于 Invalid Character '(' in mnemonic
的,另一个答案解决了这个问题。
然而,OP 的代码除了这个问题之外还有很多问题。这是(我认为的)解决这个问题的两种更好的方法。请注意,我已经更改了参数的顺序并将它们变为常量。
这个继续使用内联汇编,但使用 Extended asm instead of Basic. While I'm of the don't use inline asm 思想流派,这可能有用或至少有教育意义。
bool InterlockedCompareAndStore128B(__int64 *dest, const __int64 *oldVal, const __int64 *newVal)
{
bool result;
__int64 ovl = oldVal[0];
__int64 ovh = oldVal[1];
asm volatile ("lock cmpxchg16b %[ptr]"
: "=@ccz" (result), [ptr] "+m" (*dest),
"+d" (ovh), "+a" (ovl)
: "c" (newVal[1]), "b" (newVal[0])
: "cc", "memory");
// cmpxchg16b changes rdx:rax to the current value in dest. Useful if you need
// to loop until you succeed, but OP's code doesn't save the values, so I'm
// just following that spec.
//oldVal[0] = ovl;
//oldVal[1] = ovh;
return result;
}
除了解决原代码的问题外,还可以内联,更短。这些约束可能会使其更难阅读,但只有 1 行 asm 的事实可能有助于抵消这一点。如果您想了解约束的含义,请查看 this page (scroll down to x86 family) and the description of flag output constraints(同样,向下滚动 x86 系列 )。
作为替代方案,此代码使用内置的 gcc 并允许编译器生成适当的 asm 指令。请注意,为了获得最佳效果,必须使用 -mcx16 构建。
bool InterlockedCompareAndStore128C(__int128 *dest, const __int128 *oldVal, const __int128 *newVal)
{
// While a sensible person would use __atomic_compare_exchange_n and let gcc generate
// cmpxchg16b, gcc decided they needed to turn this into a big hairy function call:
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80878
// In short, if someone wants to compare/exchange against readonly memory, you can't just
// use cmpxchg16b cuz it would crash. Why would anyone try to exchange memory that can't
// be written to? Apparently because it's expected to *not* crash if the compare fails
// and nothing gets written. So no one gets to use that 1 line instruction and everyone
// gets an entire routine (that uses MUTEX instead of lockfree) to support this absurd
// border case. Sounds dumb to me, but that's where things stand as of 2021-05-07.
// Use the legacy function instead.
bool b = __sync_bool_compare_and_swap(dest, *oldVal, *newVal);
return b;
}
对于人群中的 kibizters,这里是 -m64 -O3 -mcx16
为最后一个生成的代码:
InterlockedCompareAndStore128C(__int128*, __int128 const*, __int128 const*):
mov rcx, rdx
push rbx
mov rax, QWORD PTR [rsi]
mov rbx, QWORD PTR [rcx]
mov rdx, QWORD PTR [rsi+8]
mov rcx, QWORD PTR [rcx+8]
lock cmpxchg16b XMMWORD PTR [rdi]
pop rbx
sete al
ret
如果有人想fiddle,here's神箭link。
您好,我正在尝试使用 gcc 7.5 版本在 Linux 上编译以下汇编代码,但不知何故出现错误
Error : Invalid Character '(' in mnemonic
bool InterlockedCompareAndStore128(int *dest,int *newVal,int *oldVal)
{
asm(
"push %rbx\n"
"push %rdi\n"
"mov %rcx, %rdi\n" // ptr to dest -> RDI
"mov 8(%rdx), %rcx\n" // newVal -> RCX:RBX
"mov (%rdx), %rbx\n"
"mov 8(%r8), %rdx\n" // oldVal -> RDX:RAX
"mov (%r8), %rax\n"
"lock (%rdi), cmpxchg16b\n"
"mov [=10=], %rax\n"
"jnz exit\n"
"inc1 %rax\n"
"exit:;\n"
"pop %rdi\n"
"pop %rbx\n"
);
}
任何人都可以建议如何解决这个问题。检查了汇编代码的许多在线链接和教程,但无法解决确切的问题。 提前感谢您的帮助。
在Windows中我可以看到上述函数的实现是:
function InterlockedCompareExchange128;
asm
.PUSHNV RBX
MOV R10,RCX
MOV RBX,R8
MOV RCX,RDX
MOV RDX,[R9+8]
MOV RAX,[R9]
LOCK CMPXCHG16B [R10]
MOV [R9+8],RDX
MOV [R9],RAX
SETZ AL
MOVZX EAX, AL
end;
对于 PUSHNV ,我在 Linux 上找不到与此相关的任何内容。所以,基本上我试图在 Linux.
上用 c++ 实现相同的功能此代码存在许多问题,我不认为告诉您如何解决具体问题对您有任何帮助。
但简短的回答是
"lock (%rdi), cmpxchg16b\n"
应该是
"lock cmpxchg16b (%rdi)\n"
Tada,现在可以编译了。好吧,如果 inc1
是一个真正的指令。
但是我不禁注意到这里的指针是int *
,也就是4个字节,而不是16个。而且这个函数没有被声明为naked
。使用 Extended asm 将使您不必手动推动所有这些寄存器,从而使这段代码比需要的慢很多。
但最重要的是,您应该真正使用 builtins,例如 __atomic_compare_exchange
,因为内联 asm 容易出错,不可移植,而且 真的 很难维护。
这里的问题是关于 Invalid Character '(' in mnemonic
的,另一个答案解决了这个问题。
然而,OP 的代码除了这个问题之外还有很多问题。这是(我认为的)解决这个问题的两种更好的方法。请注意,我已经更改了参数的顺序并将它们变为常量。
这个继续使用内联汇编,但使用 Extended asm instead of Basic. While I'm of the don't use inline asm 思想流派,这可能有用或至少有教育意义。
bool InterlockedCompareAndStore128B(__int64 *dest, const __int64 *oldVal, const __int64 *newVal)
{
bool result;
__int64 ovl = oldVal[0];
__int64 ovh = oldVal[1];
asm volatile ("lock cmpxchg16b %[ptr]"
: "=@ccz" (result), [ptr] "+m" (*dest),
"+d" (ovh), "+a" (ovl)
: "c" (newVal[1]), "b" (newVal[0])
: "cc", "memory");
// cmpxchg16b changes rdx:rax to the current value in dest. Useful if you need
// to loop until you succeed, but OP's code doesn't save the values, so I'm
// just following that spec.
//oldVal[0] = ovl;
//oldVal[1] = ovh;
return result;
}
除了解决原代码的问题外,还可以内联,更短。这些约束可能会使其更难阅读,但只有 1 行 asm 的事实可能有助于抵消这一点。如果您想了解约束的含义,请查看 this page (scroll down to x86 family) and the description of flag output constraints(同样,向下滚动 x86 系列 )。
作为替代方案,此代码使用内置的 gcc 并允许编译器生成适当的 asm 指令。请注意,为了获得最佳效果,必须使用 -mcx16 构建。
bool InterlockedCompareAndStore128C(__int128 *dest, const __int128 *oldVal, const __int128 *newVal)
{
// While a sensible person would use __atomic_compare_exchange_n and let gcc generate
// cmpxchg16b, gcc decided they needed to turn this into a big hairy function call:
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80878
// In short, if someone wants to compare/exchange against readonly memory, you can't just
// use cmpxchg16b cuz it would crash. Why would anyone try to exchange memory that can't
// be written to? Apparently because it's expected to *not* crash if the compare fails
// and nothing gets written. So no one gets to use that 1 line instruction and everyone
// gets an entire routine (that uses MUTEX instead of lockfree) to support this absurd
// border case. Sounds dumb to me, but that's where things stand as of 2021-05-07.
// Use the legacy function instead.
bool b = __sync_bool_compare_and_swap(dest, *oldVal, *newVal);
return b;
}
对于人群中的 kibizters,这里是 -m64 -O3 -mcx16
为最后一个生成的代码:
InterlockedCompareAndStore128C(__int128*, __int128 const*, __int128 const*):
mov rcx, rdx
push rbx
mov rax, QWORD PTR [rsi]
mov rbx, QWORD PTR [rcx]
mov rdx, QWORD PTR [rsi+8]
mov rcx, QWORD PTR [rcx+8]
lock cmpxchg16b XMMWORD PTR [rdi]
pop rbx
sete al
ret
如果有人想fiddle,here's神箭link。