Reading a register value into a C variable

Brian picture Brian · Jan 22, 2010 · Viewed 81.4k times · Source

I remember seeing a way to use extended gcc inline assembly to read a register value and store it into a C variable.

I cannot though for the life of me remember how to form the asm statement.

Answer

ephemient picture ephemient · Jan 22, 2010

Editor's note: this way of using a local register-asm variable is now documented by GCC as "not supported". It still usually happens to work on GCC, but breaks with clang. (This wording in the documentation was added after this answer was posted, I think.)

The global fixed-register variable version has a large performance cost for 32-bit x86, which only has 7 GP-integer registers (not counting the stack pointer). This would reduce that to 6. Only consider this if you have a global variable that all of your code uses heavily.


Going in a different direction than other answers so far, since I'm not sure what you want.

GCC Manual § 5.40 Variables in Specified Registers

register int *foo asm ("a5");

Here a5 is the name of the register which should be used…

Naturally the register name is cpu-dependent, but this is not a problem, since specific registers are most often useful with explicit assembler instructions (see Extended Asm). Both of these things generally require that you conditionalize your program according to cpu type.

Defining such a register variable does not reserve the register; it remains available for other uses in places where flow control determines the variable's value is not live.

GCC Manual § 3.18 Options for Code Generation Conventions

-ffixed-reg

Treat the register named reg as a fixed register; generated code should never refer to it (except perhaps as a stack pointer, frame pointer or in some other fixed role).

This can replicate Richard's answer in a simpler way,

int main() {
    register int i asm("ebx");
    return i + 1;
}

although this is rather meaningless, as you have no idea what's in the ebx register.

If you combined these two, compiling this with gcc -ffixed-ebx,

#include <stdio.h>
register int counter asm("ebx");
void check(int n) {
    if (!(n % 2 && n % 3 && n % 5)) counter++;
}
int main() {
    int i;
    counter = 0;
    for (i = 1; i <= 100; i++) check(i);
    printf("%d Hamming numbers between 1 and 100\n", counter);
    return 0;
}

you can ensure that a C variable always uses resides in a register for speedy access and also will not get clobbered by other generated code. (Handily, ebx is callee-save under usual x86 calling conventions, so even if it gets clobbered by calls to other functions compiled without -ffixed-*, it should get restored too.)

On the other hand, this definitely isn't portable, and usually isn't a performance benefit either, as you're restricting the compiler's freedom.