We're talking about GCC extended inline assembly here.
Originally Posted by
Absurd
First, who's to say that ""val" is referred to by %0 and "no" is referred to by %1."? Why not the other way around?
You number the output operands in the output operand list first, then the input operands, starting at 0.
For example, if you have two output operands and three input operands, the first output operand will be %0 and the second output operand %1, with the input operands being %2, %3, and %4, in the order you declare them.
The order in which you use the operands in your assembly does not matter at all; the order is determined by the declarations only.
Originally Posted by
Absurd
I don't understand the notion of "input operands" and "output operands" in that context (or in any other context, for that matter).
In this context, each input operand is
"constraint" (expression)
with commas separating multiple operands. The expression specifies some variable or expression the compiler must prepare to be accessible to your assembly snippet, with constraint telling the compiler where to put it.
Each output operand is
"constraint" (variable)
where constraint tells the compiler where a result you're interested in may be, and variable names the variable (or expression!) the compiler should move the value to.
Consider the i386 movzbl (%edi), %eax instruction, which reads one byte from the memory address pointed to by the edi register into the eax register, zero-extending the value (clearing all high bits).
If we look at the i386 mnemonics, we can see that the format allows any general register to be used as the address, and any general register as the value, so we can use the =r constraint for output and r for input operands.
We could use =A and D constraints, respectively, to get the exact form above, but why restrict the compiler?
The inline assembly snippet would be
Code:
int read_byte(const void *const address)
{
int result;
__asm__ __volatile__ ( "movzbl (%1), %0\n\t"
: "=r" (result) /* output operand */
: "r" (address) /* input operand */
: /* No clobbers this time */
);
return result;
}
The __volatile__ tells the compiler to not move code across this assembly snippet. Here, it does not matter, really.