You can learn more about GCC assembler templates in the GCC documentation. Peter Cordes has a Stackoverflow answer with a list of inline assembler if you wish to learn more. MSVC and GCC differ greatly. GCC has no knowledge of what a template does or the instructions executes. GCC instead does substitutions based upon a list of constraints - input, output, and clobber.
A GCC extended assembler template that would be a close approximation to the MSVC inline assembler could look like:
__asm__ (
"mov %%fs:0x18, %0\n\t"
"mov 0x30(%0), %0\n\t"
"mov 0x0C(%0), %0\n\t"
: "=r"(pmInfo));
In your case you need a single register to use for the internal usage. It doesn't need to be EAX but can be any register GCC has available. We use an output constraint of "=r"
that says we want GCC to choose an available register. We reference the first (and in this case the only one) constraint via %0
in the assembler template. "=r"(pmInfo)
on the constraint says that when the instructions in the template are complete the value in the register chosen will be placed into pmInfo
.
GCC extended assembler is a tricky thing to work with, and very easy to get wrong. You might be better off creating an assembler file with a function that returns a pointer to a ProcessModuleInfo structure. This eliminates the need to understand GCC's extended assembler templates, and deal with its intricacies.
Stackoverflow user DavidWohlferd wrote a GCC wiki article giving reasons why using GCC inline assembler should be avoided if possible.
If the %0
looks a bit confusing, each of the input and output operands can be given a symbolic name that can be used as an alternative instead of %
and a number in the template. The code could have looked like this:
__asm__ (
"mov %%fs:0x18, %[tempreg]\n\t"
"mov 0x30(%[tempreg]), %[tempreg]\n\t"
"mov 0x0C(%[tempreg]), %[tempreg]\n\t"
: [tempreg]"=r"(pmInfo));
The [tempreg]
in square brackets gives the operand a name as alternative to using an ordinal position. This makes it a bit easier to read the template as well.