Reading a register value into a C variable
Solution 1
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-
regTreat 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.
Solution 2
Here is a way to get ebx:
int main()
{
int i;
asm("\t movl %%ebx,%0" : "=r"(i));
return i + 1;
}
The result:
main:
subl $4, %esp
#APP
movl %ebx,%eax
#NO_APP
incl %eax
addl $4, %esp
ret
Edit:
The "=r"(i) is an output constraint, telling the compiler that the first output (%0) is a register that should be placed in the variable "i". At this optimization level (-O5) the variable i never gets stored to memory, but is held in the eax register, which also happens to be the return value register.
Solution 3
I don't know about gcc, but in VS this is how:
int data = 0;
__asm
{
mov ebx, 30
mov data, ebx
}
cout<<data;
Essentially, I moved the data in ebx
to your variable data
.
Solution 4
This will move the stack pointer register into the sp variable.
intptr_t sp;
asm ("movl %%esp, %0" : "=r" (sp) );
Just replace 'esp' with the actual register you are interested in (but make sure not to lose the %%) and 'sp' with your variable.
Solution 5
From the GCC docs itself: http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
Related videos on Youtube
Brian
Updated on August 14, 2020Comments
-
Brian over 3 years
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.
-
florin over 14 yearsAnd how do you know what is in EBX when your C code starts executing?
-
Peter Cordes about 6 yearsYou can't know what value compiler-generated code will have stored in any register when your inline
asm
statement runs, so the value is usually meaningless, and you'd be much better off using a debugger to look at register values when stopped at a breakpoint. It might make sense for a stack pointer, but there's__builtin_frame_address(0)
to get a stack address (and IIRC, cause that function to make a full stack frame, even when-fomit-frame-pointer
is enabled, like it is by default on x86.) -
Peter Cordes almost 3 yearsClosing as a duplicate of a new Q&A because the highest-voted answer here is outdated (broken with clang, unsupported by GCC). (It still happens to work with GCC, at least in simple cases.) An asm statement that does a
mov %%reg, %0
to an"=r"(var)
output is safe, too, that answer is fine.
-
-
R Samuel Klatchko over 14 yearsYou do realize that's going to read one variable, compute the sine and then store the result in a second variable.
-
Kornel Kisielewicz over 14 years@Samuel: That was an example of the syntax only.
-
ephemient over 14 yearsx86-only, of course. Microsoft's compilers for x64 and Itanium do not support inline assembly.
-
Sridarshan about 12 yearsI think the assembly will get translated to mov ebx, 30 mov dword ptr[data], ebx
-
Admin about 10 yearsWhy not just
mov data, 30
? -
Michael Petch almost 8 yearsI would use the
=rm
constraint rather than=r
. The compiler's optimizer will attempt to choose the best path. If the inline assembler happened to be in a register starved situation=r
may force it to generate less than optimal code.=rm
would give the optimizer a chance to use a memory reference if it happened to be the best choice. In this simple example it won't be an issue, but if the code is in a more complex situation then giving options to the compiler could be beneficial. -
Matthew Cole almost 7 yearsDownvoted because this is an example of how to use extended assembly in GCC, not how to get the value of a specific register into a specific variable, which is what the OP asked. By specifying the registers using
%0
and%1
, GCC will choose the register in question on your behalf. There's no assurance it will choose the register you're hoping for. -
David Wohlferd about 6 yearsQuoting from the current docs describing local registers The only supported use for this feature is to specify registers for input and output operands when calling Extended asm. So putting
i
within main() like this is unsupported. And to emphasize your point: x86 only has a limited number of registers. Removing one from general use via global register variable might slow down other critical parts of your code. Some discussion here. -
David Wohlferd about 6 years@MichaelPetch How about "=b" and an empty template string?
-
David Wohlferd about 6 yearsQuoting from the current docs describing local register variables The only supported use for this feature is to specify registers for input and output operands when calling Extended asm. So putting
i
andii
within gav() like this is unsupported. -
Peter Cordes about 6 yearsI'd highly recommend not using a global register variable, except maybe in one
.c
file containing one function as a hack. Expect a significant performance cost, especially on 32-bit x86. -
Peter Cordes almost 3 yearsNote that clang will typically pick memory if you use
"=rm"
, even if it actually needs the value in a register. It will end up storing and reloading. This is a longstanding missed-optimization in clang's inline asm support. Using"=b"(i)
should also work, just telling the compiler that the EBX holds the value ofi
after the asm statement. You may wantasm volatile
if you use this in more than one place, otherwise the compiler can assume that the asm statement always produces the same output (because the input is always the same: the empty set of inputs.) -
Ilan Schemoul almost 2 years-O5 optimization ? I've read O3 is the maximum ?