Pushing a pointer into the eax and ebx registers in GCC
If you have (inline) assembly code that requires specific parameters in EAX
/EBX
, the way to do this in gcc is to use the following:
__asm__("transmogrify %0, %1\n" : "+a"(val_for_eax), "+b"(val_for_ebx));
This uses what gcc calls inline assembly constraints which tell the compiler that the assembly code - whatever it is - expects val_for_eax
/val_for_ebx
in EAX
/EBX
(that's the a
/b
part) as well as that it will return potentially modified versions of these variables (that's the +
) in these registers as well.
Beyond that, the actual code within the asm()
statement doesn't matter to the compiler - it'll only need/want to know where the parameters %0
and %1
live. The above example will, due to a transmogrify
instruction not existing in the current x86 instruction set, fail when the assembler runs; just substitute it with something valid.
The explanations why gcc behaves this way and exactly what you can tell it to do is in the GCC manual, at:
- Extended Assembly - Assembler Instructions with C operands
- Constraints for
asm
operands, in particular the Intel/386 section of the Machine-specific Constraints list for what to say if you need to pass/retrieve a value in a specific register, and the Modifiers section about the meaning of things like the+
(to both pass and return a value; there are other such "modifiers" to the constraints)
You can specify a specific register for a variable but due to the way gcc works / the way inline assembly is implemented in gcc, doing so does not mean (!) the register is from then on reserved (out of scope) for gcc to use for its own purposes. That can only be achieved through constraints, for a specific, single asm()
block - the constraints tells gcc what to write into those registers before the placement of the actual assembly code, and what to read from them afterwards.
Since the eax
register is need all over the place in a valid program on your architecture, your strategy can't work with global variables that are bound to the specific registers. Don't do that, reserving a register globally is not a good idea.
Place the variables that are bound to registers in the particular function, as close as possible to their use.