1

我正在玩弄可执行文件/编译器/程序集——全部。

void foo(void){
}

在编译器生成的 asm 中,我碰巧注意到函数序言和结尾(Godbolt 编译器资源管理器)之间没有操作:

foo:
        push    rbp
        mov     rbp, rsp
        nop                      ## <--- this line
        pop     rbp
        ret

我用gcc -S(没有优化)编译它;编译时它消失了-O1,所以我的理论是它是用于调试的。

但是我不清楚它的目的。即使对于调试,无操作(根据定义)对程序的行为方式没有任何影响

那么为什么会有呢?


进一步的结果

  • NOP 在 GCC5 中是新的;GCC4.9.4 中不存在

  • NOP 在任何实际返回值的函数中都消失了。(从函数末尾掉下来int仍然会产生 a nop,包括main在 C89 模式下没有隐式返回 0 的 for )。

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
  • 拥有非空函数体并不能避免 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
4

0 回答 0