内联汇编没有用 clang 产生我想要的结果
Inline assembly is not producing my desired result with clang
我正在使用带 clang 的内联汇编 x86_64。我希望将 exact 程序集编译到我在源代码中指定的二进制文件中,但由于某种原因,clang 不断更改它。 这只发生在我使用 AT&T GCC 风格的程序集时,这不会发生在 MSVC __asm
我想使用 AT&T 风格的程序集,因为我的代码的其余部分大量使用 AT&T 风格我想保持一致。我的汇编代码是这样声明的:
__attribute__((naked)) void XxInternalOperation()
{
asm volatile("mov %%rcx, %%rax\n\t"
"mov %0, %%r11\n\t"
"jmpq *%%r11"
:
: "r" (jumpAddrAbsolute)
: "r11");
}
我希望我的汇编代码代表这个英特尔代码:
mov rax, rcx
mov r11, jmpAddrAbsolute ; <-- this is an unsigned long long variable
jmp r11
但 IDA 中的快速反汇编表明了其他情况:
mov rax, cs:jumpAddrAbsolute
mov rax, rcx
mov r11, rax
jmp r11
有没有办法得到我想要的确切汇编代码?
Clang 不会“改变”您的程序集。它完全按照你的要求去做,那就是:它选择一个 register(这就是 r
约束的意思)并用 %0
代替它。请注意,此寄存器也可以是 rax
,在这种情况下您的代码将不起作用。如果您希望 clang 选择内存操作数,请改用 m
约束。有关 gcc 样式内联汇编的详细信息,请参阅 the gcc manual。这是一个例子:
extern unsigned long long jumpAddrAbsolute;
__attribute__((naked)) void XxInternalOperation()
{
asm volatile("mov %%rcx, %%rax\n\t"
"mov %0, %%r11\n\t"
"jmpq *%%r11"
:
: "m" (jumpAddrAbsolute)
: "r11", "rax");
}
编译为:
movq %rcx, %rax
movq jumpAddrAbsolute(%rip), %r11
jmpq *%r11
这似乎是你想要的。
请注意,我已将 rax
标记为已损坏,因为您在第一条指令中使用了它。请进一步注意,当执行此内联汇编语句时,无法保证 rcx
保留任何特定值。编译器可以随意将其设置为任何它喜欢的值。
另请注意,编译器可能决定内联 XxInternalOperation
,在这种情况下,您的间接跳转将产生在调用者中执行尾调用的意外副作用。考虑将函数标记为 noinline
以避免这种情况。
但一般来说,在内联汇编中执行跳转或调用通常是错误方法的标志,通常会导致各种问题。如果您对决定使用此内联程序集解决的问题有一些详细信息,我也许可以向您建议更好的解决方案。
我正在使用带 clang 的内联汇编 x86_64。我希望将 exact 程序集编译到我在源代码中指定的二进制文件中,但由于某种原因,clang 不断更改它。 这只发生在我使用 AT&T GCC 风格的程序集时,这不会发生在 MSVC __asm
我想使用 AT&T 风格的程序集,因为我的代码的其余部分大量使用 AT&T 风格我想保持一致。我的汇编代码是这样声明的:
__attribute__((naked)) void XxInternalOperation()
{
asm volatile("mov %%rcx, %%rax\n\t"
"mov %0, %%r11\n\t"
"jmpq *%%r11"
:
: "r" (jumpAddrAbsolute)
: "r11");
}
我希望我的汇编代码代表这个英特尔代码:
mov rax, rcx
mov r11, jmpAddrAbsolute ; <-- this is an unsigned long long variable
jmp r11
但 IDA 中的快速反汇编表明了其他情况:
mov rax, cs:jumpAddrAbsolute
mov rax, rcx
mov r11, rax
jmp r11
有没有办法得到我想要的确切汇编代码?
Clang 不会“改变”您的程序集。它完全按照你的要求去做,那就是:它选择一个 register(这就是 r
约束的意思)并用 %0
代替它。请注意,此寄存器也可以是 rax
,在这种情况下您的代码将不起作用。如果您希望 clang 选择内存操作数,请改用 m
约束。有关 gcc 样式内联汇编的详细信息,请参阅 the gcc manual。这是一个例子:
extern unsigned long long jumpAddrAbsolute;
__attribute__((naked)) void XxInternalOperation()
{
asm volatile("mov %%rcx, %%rax\n\t"
"mov %0, %%r11\n\t"
"jmpq *%%r11"
:
: "m" (jumpAddrAbsolute)
: "r11", "rax");
}
编译为:
movq %rcx, %rax
movq jumpAddrAbsolute(%rip), %r11
jmpq *%r11
这似乎是你想要的。
请注意,我已将 rax
标记为已损坏,因为您在第一条指令中使用了它。请进一步注意,当执行此内联汇编语句时,无法保证 rcx
保留任何特定值。编译器可以随意将其设置为任何它喜欢的值。
另请注意,编译器可能决定内联 XxInternalOperation
,在这种情况下,您的间接跳转将产生在调用者中执行尾调用的意外副作用。考虑将函数标记为 noinline
以避免这种情况。
但一般来说,在内联汇编中执行跳转或调用通常是错误方法的标志,通常会导致各种问题。如果您对决定使用此内联程序集解决的问题有一些详细信息,我也许可以向您建议更好的解决方案。