cgccinline-assembly

Can I modify input operands in gcc inline assembly


We know, if I set %eax as the input, then I cannot include it into list of clobbered registers. So my question is that, is that legal to modify the value of %eax in the assembly code without any declaration in clobbered list?

__asm__ __volatile__("inc %0" :: "a"(num) : "%eax"); // illegal
__asm__ __volatile__("inc %0" :: "a"(num));       // Can I modify %eax?

Solution

  • No, if the assembly code changes an input register, it must also be listed as an output register, or as an in-out register, by using "+" instead of "=" in the constraint.

    Examples:

    __asm__ __volatile__("..." : "+r"(num));
    __asm__ __volatile__("..." : "=a"(dummy) : "a"(num));
    __asm__ __volatile__("..." : "=r"(dummy) : "0"(num));
    

    The first example specifies num as both an input and an output. This will overwrite the prior value of num, which may be undesirable if the operand is clobbered rather being set to a useful value.

    The second example explicitly uses eax for both input and output. It directs the output to a dummy variable so as to not corrupt the actual input variable num.

    The third example uses a dummy output, to avoid modifying num, and also avoids specifying eax explicitly, allowing the compiler to choose which register to use. The "0" constraint tells the compiler to use the same register as operand 0 for this input operand.


    The inline-assembly tag wiki links some guides and tutorials, and the GCC manual which says:

    Warning: Do not modify the contents of input-only operands (except for inputs tied to outputs). The compiler assumes that on exit from the asm statement these operands contain the same values as they had before executing the statement. It is not possible to use clobbers to inform the compiler that the values in these inputs are changing. One common work-around is to tie the changing input variable to an output variable that never gets used. Note, however, that if the code that follows the asm statement makes no use of any of the output operands, the GCC optimizers may discard the asm statement as unneeded (see Volatile).