mrjbom wrote:
In general, is the "memory" clobber needed if there have been changes in memory or registers after the assembly code, right?
The memory clobber is needed for two things:
For one, it is needed if some memory known to the compiler has changed. This can be stack variables or static memory. Generally something that is not a direct operand of the asm statement. This can be useful if you are in an asm goto statement and need to output some data. This use is pretty rare, though. For example, let's say you want to read esp.
Code:
asm("movl %%esp, %0" : "=rm"(sp));
This is enough. No clobber needed. Even if the compiler allocates sp in memory for some reason, the instruction only writes to a direct operand, which the compiler already knows about.
For two, the clobber is needed if the statement depends on or changes some global state that is hard to quantify and impossible to express in C. For example, there is the compiler barrier
Code:
asm("" ::: "memory");
This prevents the compiler from reordering memory accesses across it. Which can be useful in synchronization primitives. In most architectures, you want a memory barrier for this, though. Notice that x86, while having strong memory ordering by default, still allows loads to be reordered above independent stores. The only way to prevent that is to execute a locked instruction.
Another example would fenv access:
Code:
uint16_t cw = ...; asm("fldcw %0" :: "m"(cw) : "memory");
This tells the compiler that statements afterwards depend on this one, so they cannot be reordered. Which is true: The x87 control word is input to all x87 calculations later on. But there is no way to tell the compiler that it is only floating-point calculations that depend on this, so the memory clobber is the best available thing.
In your case, the pushf modifies memory, yes, but only memory the compiler cannot touch (namely memory below the stack pointer). If you were on x86_64 with red zone, this would be different, but on i386, that memory is always off limits to the compiler.