Why is there a NOP in void functions in unoptimized GCC output?

91 Views Asked by At

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 int function still produces a nop, including for main in 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
0

There are 0 best solutions below