Assembly question
Hi,
Long time ago (older gcc) this code snippet used to compile. Now it doesn't. Do you asm gurus have any idea what is wrong?
void p_memset_dword( void *d, int b, int l )
{
__asm__ ("rep\n\t"
"stosl\n\t"
:
: "D" (d), "a" (b), "c" (l)
: "memory","edi", "eax", "ecx"
);
}The compiler says:a.c: In function `p_memset_dword':
a.c:9: Invalid `asm' statement:
a.c:9: fixed or forbidden register 0 (ax) was spilled for class AREG.
Thanks,
Pista
Quoted 7 lines · Szekeres Istvan
void
p_memset_dword( void *d, int b, int l ){ __asm__ ("rep\n\t" "stosl\n\t" : : "D" (d), "a" (b), "c" (l) : "memory","edi", "eax", "ecx"
An input or output operand is implicitly clobbered, so it should be written as:
: "D" (d), "a" (b), "c" (l) : "memory"
Or so.
Signature · 5 lines
Mark Zealey (aka JALH on irc.openprojects.net: #zealos and many more) [email protected]; [email protected] UL++++>$ G!>(GCM/GCS/GS/GM) dpu? s:-@ a17! C++++>$ P++++>+++++$ L+++>+++++$ !E---? W+++>$ !w--- r++ !t---?@ !X---? !R- !tv b+ G+++ e>+++++ !h++* r!-- y--
Quoted 10 lines · Mark Zealey
Quoted 5 lines · Szekeres Istvan
void
p_memset_dword( void *d, int b, int l ){__asm__("rep\n\t" "stosl\n\t": : "D" (d), "a" (b), "c" (l) : "memory","edi", "eax", "ecx"
An input or output operand is implicitly clobbered, so it should be
^^^^^
I had expected gcc specialists to jump on that one: if you don't explicitly tell gcc that an input is clobbered, it may reuse it later if it needs the same value. So the clobbers are necessary...
Your statement about output operands is also incorrect, since clobbered
means that the register has an unknown value, which can not be used for
_anything_, while outputs are results from the statement and they'll
likely be used later (if none of the outputs is ever used and the asm statement is not marked volatile, gcc will not even bother to emit it).
Regards,
Gabriel.
Quoted 9 lines · Gabriel Paubert
Quoted 4 lines · Mark Zealey
Quoted 1 line · Szekeres Istvan
void
p_memset_dword( void *d, int b, int l ){__asm__("rep\n\t""stosl\n\t"
Quoted 1 line
Quoted 1 line
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
: : "D" (d), "a" (b), "c" (l) : "memory","edi", "eax", "ecx"
An input or output operand is implicitly clobbered, so it should be
^^^^^I had expected gcc specialists to jump on that one: if you don't explicitly tell gcc that an input is clobbered, it may reuse it later if it needs the same value. So the clobbers are necessary...
: : "D" (d), "a" (b), "c" (l) : "memory","edi", "eax", "ecx"
... is correct. Registers EDI, EAX, and ECX are altered and memory is changed. Nothing having to do with the 'input' is altered in any meaningful sense. You alter an 'input' by doing something like:
pushl %ebx ..... code popl %eax ; Input value of ebx is destroyed
Passed parameters are (usually) passed on the stack. They are local and disappear when the call returns, i.e.,
pushl string ; 4 - byte address
call puts ; call function
addl $4, esp ; Level stack
GCC may optimize in-line and not bother to push a value that is readily accessible to the in-line function. That value is not clobbered in any way. The in-line function doesn't have to 'return' since it's in-line. Therefore the return address isn't on the stack either. When setting up 'clobbers', you have observe the registers that are used and declare whether or not memory is altered. That's all. For instance, we see EAX as a clobbered register. GCC may decide that it is a scratch-register so it doesn't bother to save/restore its value. On the other hand, if you didn't tell GCC that you destroyed EAX, it's a bug and a hard-to-find bug because most of the time, the code will work.
Cheers,
Dick Johnson
Penguin : Linux version 2.4.18 on an i686 machine (797.90 BogoMips).
Windows-2000/Professional isn't.
Quoted 16 lines · Richard Johnson
Quoted 9 lines · Gabriel Paubert
Quoted 8 lines · Mark Zealey
Quoted 6 lines · Szekeres Istvan
void
p_memset_dword( void *d, int b, int l ){
__asm__("rep\n\t""stosl\n\t" : : "D" (d), "a" (b), "c" (l) : "memory","edi", "eax", "ecx"); }Quoted 5 lines
Quoted 1 line
An input or output operand is implicitly clobbered, so it should be
^^^^^
I had expected gcc specialists to jump on that one: if you don't explicitly tell gcc that an input is clobbered, it may reuse it later if it needs the same value. So the clobbers are necessary...
Quoted 4 lines
: : "D" (d), "a" (b), "c" (l) : "memory","edi", "eax", "ecx"... is correct. Registers EDI, EAX, and ECX are altered and memory is changed. Nothing having to do with the 'input' is altered in any meaningful sense.
As usual you are completely wrong. Clobbers can be used ONLY for registers that do not already appear in either the input or output list. In this case, it is the input registers that are modified. You have to use notation that makes that explicit.
The correct way to write this asm statement with GCC 2.95 or later is
asm volatile
("rep; stosl"
: "+D" (d), "+c" (l) /* read and write edi, ecx */
: "a" (b)
: "memory");With earlier versions you have to use a more verbose notation.
Some further notes:
rep stosl doesn't change %eax, so a plain input parameter can be used for that argument.
GCC assumes that any asm with output parameters has no side effects. The memory clobber doesn't count. Therefore, it will notice that d and l are not used again and delete the whole asm statement, unless you qualify it with 'volatile'.
There is no point in using __asm__ instead of asm, unless you are writing code which has to compile with -pedantic on.
zw