使用内联asm检索x64寄存器值 [英] Retrieving x64 register values with inline asm

查看:181
本文介绍了使用内联asm检索x64寄存器值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

让我们说我想将r8的内容放在一个变量中,是否可以编写这样的内容:

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

解决方案

鉴于大多数寄存器的易变性,目前尚不清楚为什么需要将特定寄存器的内容放入变量中.

GNU C仅对原始8个寄存器具有特定寄存器约束, .对于r8..r15,唯一的选择(为避免在asm语句内需要mov指令)是register-asm变量.

 register long long my_var __asm__ ("r8");
 __asm__ ("" :"=r"(my_var));               // guaranteed that r chooses r8

您可能希望使用额外的输入/输出约束来控制对的值进行采样的 where . (例如,"+rm"(some_other_var)将使该asm语句成为函数中数据依赖关系链的一部分,但这也将阻止常量传播和其他优化.)asm volatile可能有助于控制顺序,但这不能保证. >


有时 可以使用本地寄存器作为操作数来省略__asm__ ("" :"=r"(my_var));语句,但是只有在使用它的情况下,它才能保证有效:

编译为

It is not clear why would you need to put contents of a specific register into a variable, given a volatile nature of the most of them.

GNU C only has specific-register constraints for the original 8 registers, like "=S"(rsi). For r8..r15, your only option (to avoid needing a mov instruction inside the asm statement) is a register-asm variable.

 register long long my_var __asm__ ("r8");
 __asm__ ("" :"=r"(my_var));               // guaranteed that r chooses r8

You may want to use an extra input/output constraint to control where you sample the value of r8. (e.g. "+rm"(some_other_var) will make this asm statement part of a data dependency chain in your function, but that will also prevent constant-propagation and other optimizations.) asm volatile may help with controlling the ordering, but that's not guaranteed.


It sometimes works to omit the __asm__ ("" :"=r"(my_var)); statement using the register local as an operand, but it's only guaranteed to work if you do use it: https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables. (And see discussion in comments on a previous version of this answer which suggested you could skip that part.) It doesn't make your code any slower, so don't skip that part to make sure your code is safe in general.

The only supported use for this feature is to specify registers for input and output operands when calling Extended asm (see Extended Asm). This may be necessary if the constraints for a particular machine don’t provide sufficient control to select the desired register. To force an operand into a register, create a local variable and specify the register name after the variable’s declaration. Then use the local variable for the asm operand and specify any constraint letter that matches the register

P.S. This is a GCC extension that may not be portable, but should be available on all compilers that support GNU C inline asm syntax.

gcc doesn't have specific-register constraints at all for some architectures, like ARM, so this technique is the only way for rare cases where you want to force specific registers for input or output operands.


Example:

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
}

compiled with gcc7.3 -O3 on the Godbolt compiler explorer

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

这篇关于使用内联asm检索x64寄存器值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆