Gcc 使用内联asm检索x64寄存器值
我想知道是否有任何方法允许我指定eax、ebx、ecx和edx以外的任何对象作为输出操作数 假设我想把r8的内容放在一个变量中,是否可以这样写:Gcc 使用内联asm检索x64寄存器值,gcc,assembly,x86-64,Gcc,Assembly,X86 64,我想知道是否有任何方法允许我指定eax、ebx、ecx和edx以外的任何对象作为输出操作数 假设我想把r8的内容放在一个变量中,是否可以这样写: __asm__ __volatile__ ("" :"=r8"(my_var) : /* no input */ );
__asm__ __volatile__ (""
:"=r8"(my_var)
: /* no input */
);
根据这里的答案,这应该是可能的:
根据这里的答案,这应该是可能的:
鉴于大多数寄存器的易变性,不清楚为什么需要将特定寄存器的内容放入变量中 GNU C仅对原始8个寄存器具有特定的寄存器约束。对于
r8..r15
,您唯一的选择(避免在asm
语句中需要mov
指令)是寄存器asm变量
register long long my_var __asm__ ("r8");
__asm__ ("" :"=r"(my_var)); // guaranteed that r chooses r8
您可能希望使用额外的输入/输出约束来控制对r8
的值采样的位置。(例如,“+rm”(some_other_var)
将使此asm语句成为函数中数据依赖链的一部分,但这也将阻止持续传播和其他优化。)asm volatile
可能有助于控制顺序,但这并不能保证
它有时可以省略
\uuu asm\uuu(“:”=r“(my\u var))使用寄存器本地作为操作数的代码>语句,但仅当确实使用它时,才能保证它工作:。(请参阅本答案上一版本的评论中的讨论,其中建议您可以跳过该部分。)它不会使您的代码变得更慢,因此不要跳过该部分,以确保您的代码总体上是安全的
此功能支持的唯一用途是在调用扩展asm时为输入和输出操作数指定寄存器(请参阅扩展asm)。如果特定机器的约束不能提供足够的控制来选择所需的寄存器,这可能是必要的。要将操作数强制放入寄存器,请创建一个局部变量,并在变量声明后指定寄存器名称。然后对asm操作数使用局部变量,并指定与寄存器匹配的任何约束字母
另外,这是一个GCC扩展,它可能不可移植,但应该可以在所有支持GNU C内联asm语法的编译器上使用
对于某些体系结构(如ARM),gcc根本没有特定的寄存器约束,因此对于少数情况下需要强制输入或输出操作数使用特定寄存器的情况,此技术是唯一的方法
例如:
int get_r8d(void) {
register long long my_var __asm__ ("r8");
__asm__ ("" :"=r"(my_var)); // guaranteed that r chooses r8
return my_var * 2; // do something interesting with the value
}
编撰
鉴于大多数寄存器的易变性,不清楚为什么需要将特定寄存器的内容放入变量中
GNU C仅对原始8个寄存器具有特定的寄存器约束。对于r8..r15
,您唯一的选择(避免在asm
语句中需要mov
指令)是寄存器asm变量
register long long my_var __asm__ ("r8");
__asm__ ("" :"=r"(my_var)); // guaranteed that r chooses r8
您可能希望使用额外的输入/输出约束来控制对r8
的值采样的位置。(例如,“+rm”(some_other_var)
将使此asm语句成为函数中数据依赖链的一部分,但这也将阻止持续传播和其他优化。)asm volatile
可能有助于控制顺序,但这并不能保证
它有时可以省略\uuu asm\uuu(“:”=r“(my\u var))使用寄存器本地作为操作数的代码>语句,但仅当确实使用它时,才能保证它工作:。(请参阅本答案上一版本的评论中的讨论,其中建议您可以跳过该部分。)它不会使您的代码变得更慢,因此不要跳过该部分,以确保您的代码总体上是安全的
此功能支持的唯一用途是在调用扩展asm时为输入和输出操作数指定寄存器(请参阅扩展asm)。如果特定机器的约束不能提供足够的控制来选择所需的寄存器,这可能是必要的。要将操作数强制放入寄存器,请创建一个局部变量,并在变量声明后指定寄存器名称。然后对asm操作数使用局部变量,并指定与寄存器匹配的任何约束字母
另外,这是一个GCC扩展,它可能不可移植,但应该可以在所有支持GNU C内联asm语法的编译器上使用
对于某些体系结构(如ARM),gcc根本没有特定的寄存器约束,因此对于少数情况下需要强制输入或输出操作数使用特定寄存器的情况,此技术是唯一的方法
例如:
int get_r8d(void) {
register long long my_var __asm__ ("r8");
__asm__ ("" :"=r"(my_var)); // guaranteed that r chooses r8
return my_var * 2; // do something interesting with the value
}
编撰
这样说并不完全正确,如果有效,您将始终确保变量由寄存器支持:许多人认为foo
变量将始终由寄存器支持。唯一的保证是,内联程序集末尾的r8
中包含的任何内容都将移动到变量foo
。在模板之前或之后,通常不能对r8
说任何其他内容。在您的示例中,您可能应该放下指针int*foo
并使用int-foo
,为了匹配问题,可以使用my_var
而不是foo。基本上是通过自身注册int-foo asm(“r8”)
不必将r8
的内容移动到foo
。当这个变量应用于扩展内联汇编语句时,它就有了意义。@MichaelPetch这正是我给的引号所说的:“然后对asm操作数使用局部变量,并指定与寄存器匹配的任何约束字母”是的,这是引号所说的,但不是你自己说的。你引用的文件是正确的,但你可能会给人一个关于实际情况的错误印象。您的示例实际上没有提到必须在assemblytemplate中使用foo
来执行
get_r8d():
lea eax, [r8+r8] # gcc can use it directly without a MOV first
ret