Accessing CPU registers from C

I recently played with inline assmbly in C and wondered if I could directly access the register from a variable

Something like that:

volatile uint64_t* flags = RFLAGS;

      

Where RFLAGS is the CPU flags register. Obviously the above code does not compile, but I was wondering if there was a similar way to achieve the desired result.

Compiling for Ubuntu x86_64 with gcc

+3


source to share


2 answers


Yes of course. You can PUSHF

, PUSHFD

or PUSHFQ

use flags, and insert them in a different register. For example:

unsigned int flags;
__asm{
  pushfd
  pop edx
  mov flags, edx
}

      

For gcc under Ubuntu using AT&T syntax, you may find the following more immediately applicable:



unsigned int flags:
__asm__("pushf\n\t"
        "pop edx\n\t"
        "movl edx, flags");

      

From there, you can watch them at your leisure!

+3


source


You can get the value of the flags register through the built-in asm, but this operation is not useful because you have no control over the sequencing of access with respect to other operations. In particular, you most likely want the flags resulting from some arithmetic operation to be available at the beginning of your asm block, but there is no way to express this restriction to the compiler. For example, suppose you wrote:

z = x + y;
__asm__ ( "pushf ; pop %0" : "=r"(flags) );

      

Perhaps you can expect the flags resulting from the addition to be available. However, the compiler could choose:

  • change the order of arithmetic after asm, since neither has a result that depends on the other.
  • adjust the stack pointer with add

    / in sub

    between, resetting the flags.
  • use lea

    instead add

    to implement add without creating flags.
  • completely eliminate the addition based on the determination that the result is not used.
  • and etc.


The same principle applies to access to any register that can be changed by the code that the compiler generates. There's a syntax (in GCC / "GNU C") for accessing registries not covered by this issue; it looks like this:

register int var __asm__("regname");

      

where regname

is replaced by the name of the register. This is mostly useless for most purposes, but it can allow you to control the use of registers for I / O limits for asm, and some targets are persistently stored in public registers (a pointer to local storage is the most common) which can be useful in some situations ...

+7


source







All Articles