'C - Read and set assembler registers
I need to be able to access assembly registers from my C code. I there a easy way to set the value of a register to the value of a variable and get the value of a register as a variable?? Hope this makes sense...
Solution 1:[1]
If you really want to know the value of a register while some code is executing, it makes much more sense to use a debugger. (Like gdb with layout asm; layout reg). Seeing register values without also seeing the asm code makes little sense.
See the links and guides in the x86 wiki.
However, with GNU inline asm, you could just do something like
int eax_snapshot;
asm volatile (
""
: "=a" (eax_snapshot)
// no inputs, no clobbers
);
// any amount of intervening code
printf("eax was %x\n", eax_snapshot); // print whatever eax had at the point where the inline asm appeared in program order
The a constraint means the operand must use the %eax register. The body of your inline asm then becomes a no-op, because your output operand is already where you told the compiler it will be.
There's no guarantee that gcc won't emit code that clobbers %eax before the asm block. This is why it makes little sense to do this. volatile tells the compiler not to re-order the asm statement with respect to other source instructions, but optimizations could still mean that earlier initializations are folded into later code that uses them. Or vice versa. Using a combination of this with an explicit-register local variable might help avoid gcc using your chosen register as a scratch register for computing other things, though. (see below).
To set a register, use inline asm with an "a" constraint to force that operand's value to be in %eax (or %ebx for a "b" constraint, etc, see the docs for the x86-specific machine constraints) at the point where the inline asm appears. If you want to actually use that register value, do it from inside the inline asm statement, or else the register may be overwritten with something else.
You can also declare variables the must be allocated in a specific register, but I think using them without initialization makes the compiler unhappy. (Code transformation passes that detect undefined behaviour such as this could cause a problem. IDK.) The syntax would be
register int eax asm ("eax"); // don't do this to read eax, it probably doesn't do what you think it would
The docs make it sound like using it for reading registers is not going to be a good idea. However, for setting a register value, this may work. (As long as the register allocator takes your hint and does keep that variable in the requested register.)
register int foo asm("regname") sometimes still works in practice with GCC the way it used to (before they changed the documentation to unsupport it except for inline asm). But IIRC not always.
Clang generally doesn't do anything beyond constraining what choices "r" or "=r" makes for an Extended asm statement, the minimum the GCC documentation guarantees. So even if the now-undocumented (and thus unsupported) usage of it without an actual asm statement happens to work on your version of GCC for your code for reading or writing a register at some point in your program, it's likely not portable to clang.
Don't do this unless you have a very good reason. It's highly unlikely to be useful for normal programming. Normal inline asm, or calling functions, is a better way to combine C and asm. This is only useful if you want some kind of kludgy poking at the internal state of your program.
Reading a register this way inside a normal function means the compiler could have put some instructions before your asm statement which modify that register, so you can't be sure it actually came from an asm caller, if you're trying to invent a custom calling convention.
Since you haven't given a use-case for why you want this, I strongly urge you not to write code that does this. It just sounds ugly.
Solution 2:[2]
Since you are using gcc, here are the docs on using the asm template in gcc: https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#AssemblerTemplate
In order to set the value of a register, you would do the following:
uint64_t rax = 0;
__asm__ __volatile__("mov %0, %%rax\n\t"
: /* no output */
: "a" (rax)
: "%rax");
In order to read the value of a register, you would do the following:
uint64_t rax;
__asm__ __volatile__("mov %%rax, %0\n\t"
: "=a"(rax)
: /* no input */
: /* no clobbers */);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 |
