据我所知道的,唯一的区别__asm { ... };,并__asm__("...");是第一个使用mov eax, var第二个使用movl %0, %%eax与:"=r" (var)结尾.还有什么其他差异?那又怎么样asm?
我希望能够%rbp在内联asm中使用基指针寄存器().这样的玩具示例是这样的:
void Foo(int &x)
{
asm volatile ("pushq %%rbp;" // 'prologue'
"movq %%rsp, %%rbp;" // 'prologue'
"subq $12, %%rsp;" // make room
"movl $5, -12(%%rbp);" // some asm instruction
"movq %%rbp, %%rsp;" // 'epilogue'
"popq %%rbp;" // 'epilogue'
: : : );
x = 5;
}
int main()
{
int x;
Foo(x);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我希望,因为我使用通常的序幕/结尾函数调用方法来推送和弹出旧的%rbp,这样就可以了.但是,当我尝试在内x联asm之后访问时,它会出现故障.
GCC生成的汇编代码(略微剥离)是:
_Foo:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
# INLINEASM
pushq %rbp; // prologue
movq %rsp, …Run Code Online (Sandbox Code Playgroud) 考虑以下小功能:
void foo(int* iptr) {
iptr[10] = 1;
__asm__ volatile ("nop"::"r"(iptr):);
iptr[10] = 2;
}
Run Code Online (Sandbox Code Playgroud)
使用gcc,它将编译为:
foo:
nop
mov DWORD PTR [rdi+40], 2
ret
Run Code Online (Sandbox Code Playgroud)
请特别注意,即在第一次写iptr,iptr[10] = 1根本不会发生:内联汇编nop是在函数的第一件事,只有最后写2(会出现ASM呼叫后)。显然,编译器决定只需要提供其iptr 自身值的最新版本,而不需要提供其指向的内存。
我可以告诉编译器,内存必须是最新的memory,就像这样:
void foo(int* iptr) {
iptr[10] = 1;
__asm__ volatile ("nop"::"r"(iptr):"memory");
iptr[10] = 2;
}
Run Code Online (Sandbox Code Playgroud)
结果为预期的代码:
foo:
mov DWORD PTR [rdi+40], 1
nop
mov DWORD PTR [rdi+40], 2
ret
Run Code Online (Sandbox Code Playgroud)
但是,这太强了,因为它告诉编译器必须写入所有内存。例如,在以下功能中:
void foo2(int* iptr, long* …Run Code Online (Sandbox Code Playgroud) 可能重复:
如何访问c变量以进行内联汇编操作
鉴于此代码:
#include <stdio.h>
int main(int argc, char **argv)
{
int x = 1;
printf("Hello x = %d\n", x);
}
Run Code Online (Sandbox Code Playgroud)
我想在内联汇编中访问和操作变量x.理想情况下,我想使用内联汇编更改其值.GNU汇编程序,并使用AT&T语法.假设我想将x的值更改为11,就在printf语句之后,我将如何进行此操作?
是否可以使用 GCC 或 Clang 编写内联汇编(英特尔语法),而无需了解 clobber 列表“东西”?
我会猜测“不”,因为 clobber 列表“东西”确保您不会覆盖编译器写入的寄存器(立即在您的内联汇编开始之前)?