I'm toying around with executables/compilers/assembly - the whole lot.
void foo(void){
}
In the compiler-generated asm, I happened to notice there was a no-op between the function prologue and epilogue (Godbolt compiler explorer):
foo:
push rbp
mov rbp, rsp
nop ## <--- this line
pop rbp
ret
I compiled it with gcc -S (no optimisations); it's gone when compiling with -O1, so my theory is that it's for debugging.
However I'm not clear on its purpose. Even for debugging, having a no-op - by definition - makes no difference to how the program behaves, whatsoever.
So why is there?
Further results
The NOP is new in GCC5; not present in GCC4.9.4
The NOP is gone in any function that actually returns a value. (Falling off the end of an
intfunction still produces anop, including formainin C89 mode without implicit return 0).
int bar(int x){
return x;
}
bar:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov eax, DWORD PTR [rbp-4]
pop rbp
ret
- Having a non-empty function body isn't what avoids the NOP:
int sink;
void baz(){
sink = 0;
}
baz:
push rbp
mov rbp, rsp
mov DWORD PTR sink[rip], 0
nop ## <--- Still present
pop rbp
ret
int main(void){
//return 0; // -std=gnu89 to not implicitly return 0; produces a nop
}
# GCC11 defaults to -std=gnu17 so return 0 is implicit
main:
push rbp
mov rbp, rsp
mov eax, 0 # replaced with a NOP with -std=gnu89
pop rbp
ret