Update: See Eric Postpischil’s answer, I think he is right.
I found it on this page when I study inline assembly code.
static inline char * strcpy(char * dest,const char *src)
{
int d0, d1, d2;
__asm__ __volatile__( "1:\n\t"
"lodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
: "=&S" (d0), "=&D" (d1), "=&a" (d2)
: "0" (src),"1" (dest)
: "memory");
return dest;
}
I am confused that why three temp variables is needed? I try to implement without using them.
static inline char * strcpy(char * dest,const char *src)
{
__asm__ __volatile__( "1:\n\t"
"lodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
/* : "=&S" (d0), "=&D" (d1), "=&a" (d2) */
:
: "S" (src),"D" (dest)
: "memory", "esi", "edi", "al");
return dest;
}
But I got errors when compile it with gcc.
inline.c: In function ‘strcpy’:
inline.c:6:9: error: can't find a register in class ‘SIREG’ while reloading ‘asm’
inline.c:6:9: error: ‘asm’ operand has impossible constraints
The original code is trying to deal with the fact that the
lodsbandstosbinstructions modify registers %ESI, %EDI, and %AL. To do this, it has definedd0,d1, andd2so that it can declare them as outputs from the assembly code. It does not actually want these values as outputs, so it does not use them after the assembly. However, because they are outputs, the compiler knows that they are modified by the assembly code, so the compiler knows not to keep any values in those registers that it wants to remain unchanged through the assembly code.It should be possible to do this in another way, and your code better expresses the semantics: It says inputs are provided in %ESI and %EDI and that memory, %ESI, %EDI, and %AL are altered. The original code asserts that %ESI, %EDI, and %AL are outputs, which is not the true intent; they are unwanted byproducts, not desired outputs.
However, your version of GCC is different from mine (Apple/clang-418.0.60); mine accepts the code you wrote without error. I suspect your GCC is confused by the fact that %ESI is specified both as an input register (by
"S"after the second colon) and as something that is clobbered (by"esi"after the third colon). Perhaps this was a shortcoming in GCC that was later fixed, and the original code was working around that shortcoming.