When there are no functions being called by the C code, gcc decides to use negative offsets in the stack instead of sub'ing rsp. But if there's a call inside an inline asm, it will trash the "stack" with a return pointer, and that might lead to random code being run, for example: $ cat main.c void __attribute__((noinline)) dummy(void) {} void __attribute__((noinline)) runtwice(void (**x)(void)) { void (*f)(void) = x[0]; asm("movq $0x00, -16(%rsp)\n\t"); #ifdef ONE_IN_C f(); #else asm("call *%0\n\t"::"m"(f)); #endif asm("call *%0\n\t"::"m"(f)); } int main() { void (*f[])(void) = { dummy }; runtwice(f); return 0; } $ gcc -O2 -g -o main-noc.o -c main.c $ gcc -O2 -g -o main-c.o -c main.c -DONE_IN_C $ gcc -o main-noc main-noc.o $ gcc -o main-c main-c.o $ ./main-noc Segmentation fault $ ./main-c $
The disassembly of the runtwice function gives: 0000000000000010 <runtwice>: (no C functions being called) 10: 48 8b 07 mov (%rdi),%rax 13: 48 89 44 24 f8 mov %rax,-0x8(%rsp) 18: 48 c7 44 24 f0 00 00 movq $0x0,-0x10(%rsp) 1f: 00 00 21: ff 54 24 f8 callq *-0x8(%rsp) 25: ff 54 24 f8 callq *-0x8(%rsp) 29: c3 retq 0000000000000010 <runtwice>: (one C function being called) 10: 48 83 ec 18 sub $0x18,%rsp 14: 48 8b 07 mov (%rdi),%rax 17: 48 89 44 24 08 mov %rax,0x8(%rsp) 1c: 48 c7 44 24 f0 00 00 movq $0x0,-0x10(%rsp) 23: 00 00 25: ff d0 callq *%rax 27: ff 54 24 08 callq *0x8(%rsp) 2b: 48 83 c4 18 add $0x18,%rsp 2f: c3 retq I put that asm("movq $0x00, -16(%rsp)\n\t"); there to explicitly clear the next pointer that would be called, but it could contain anything on a more complex program. I did not find in the documentation whether it is possible to hint the inline asm block that a function is being called inside it. -- Summary: Stack trashed by call inside inline asm Product: gcc Version: 4.4.3 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: ramiro dot polla at gmail dot com GCC target triplet: x86_64-linux-gnu http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44975