-O1 and GCC segment faults for inline assemblers
I
detected a weird segfault in my code, if this could be a GCC bug or just my fault, I’d like to hear from you!
The function looks like this:
void testMMX( ... ) {
unsigned long a = ...;
unsigned char const* b = ...;
unsigned long c = ...;
__asm__ volatile (
"pusha;"
);
__asm__ volatile ( "mov %0, %%eax;" : : "m"( a ) : "%eax" ); with "r"( a ) it just works fine!
__asm__ volatile ( "add %0, %%eax;" : : "m"( b ) : "%eax" );
__asm__ volatile ( "mov %0, %%esi;" : : "m"( c ) : "%eax", "%esi" );
__asm__ volatile (
"sub %eax, %esi;"
"dec %esi;"
"movd (%esi), %mm0;"
"popa;"
);
}
If I compile it with -O0, it works fine. But it will have a segfault with -O1 and -O2. It took me a long time to figure out that this segfault was caused by a missing frame pointer. The pusha instruction increases the stack size by 4*8=32 bytes (x86_32), so ESP should also increase. But the GCC does not recognize this. If I add ESP fix manually
__asm__("add $32, %esp")
Or use the “-fno-omit-frame-pointer” flag in gcc, I can compile and run it with -O1 and -O2 without any errors!
So my question now is: if frame-pointer-omission is enabled, why doesn’t gcc use any push/pop inline assembler operations to tweak ESP? Is this a gcc error? Will the GCC even be able to detect this? Am I missing something?
It would be interesting to solve this problem.
Thanks in advance!
Solution
No – GCC cannot detect this. It does not perform any analysis on the instructions that appear in the ASM
block. It is your responsibility to notify the compiler of any side effects. Can you explain what test you are doing?
Also, you should consider using a single asm
block for this code; Volatile
may prevent the reordering of ASM
blocks, but you cannot assume this yields consecutive instructions .