使用内联asm检索x64寄存器值

时间:2018-04-24 20:02:46

标签: gcc assembly x86-64

我想知道是否有任何方法可以让我指定除了eax,ebx,ecx和edx之外的任何东西作为输出操作数。

假设我想将r8的内容放在一个变量中,是否可以这样写:

  __asm__ __volatile__ (""  
                        :"=r8"(my_var) 
                        : /* no input */                             
                        );            

2 个答案:

答案 0 :(得分:1)

应该可以,基于这里的答案: https://stackoverflow.com/a/43197401/3569229

#include <stdint.h>

uint64_t getsp( void )
{
    uint64_t sp;
    asm( "mov %%r8, %0" : "=rm" ( sp ));
    return sp;
}

您可以在此处找到注册名称列表:https://www3.nd.edu/~dthain/courses/cse40243/fall2015/intel-intro.html

因此,您的上述代码将更改为:

__asm__ __volatile__ ("mov %%r8, %0"  
                        :"=rm"(my_var) 
                        : /* no input */                             
                        );            

答案 1 :(得分:0)

目前尚不清楚为什么你需要将特定寄存器的内容放入变量中,因为大多数寄存器具有易变性。

GNU C仅对原始的8个寄存器like "=S"(rsi)具有特定寄存器约束。对于r8..r15,唯一的选择(避免在mov语句中需要asm指令)是register-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可能有助于控制排序,但这不是保证。

有时使用寄存器local作为操作数来省略__asm__ ("" :"=r"(my_var));语句,但只有在使用它时才能保证工作:https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables。 (并参见对此答案的先前版本的评论中的讨论,建议您可以跳过该部分。)它不会使您的代码变慢,所以不要跳过该部分以确保您的代码一般是安全的。 / p>

  

此功能唯一支持的用途是在调用Extended asm 时指定输入和输出操作数的寄存器(请参阅扩展Asm)。如果特定机器的约束不能提供足够的控制来选择所需的寄存器,则这可能是必要的。要强制操作数进入寄存器,请创建局部变量并在变量声明后指定寄存器名称。然后使用局部变量作为asm操作数,并指定与寄存器匹配的任何约束字母

P.S。这是一个可能不可移植的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
}

使用gcc7.3 -O3 on the Godbolt compiler explorer

编译
get_r8d():
    lea     eax, [r8+r8]        # gcc can use it directly without a MOV first
    ret