Retrieving x64 register values with inline asm

sebastiaan peters

I was wondering if there was any way that would allow me to specify anything other than eax, ebx, ecx and edx as output operands.

Lets say I want to put the content of r8 in a variable, Is it possible to write something like this :

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

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

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related