c/c++の関数ポインタがどのように動作するか(未完了)

1627 ワード

void fn(){};                      5:   55                      push   %ebp             
int main(){                       6:   89 e5                   mov    %esp,%ebp            
    void (*pf)(void)=&fn;         8:   83 e4 f0                and    $0xfffffff0,%esp 
    (*pf)();                      b:   83 ec 10                sub    $0x10,%esp       
}                                 e:   e8 00 00 00 00          call   13 <_main+0xe>   
                                 13:   c7 44 24 0c 00 00 00    movl   $0x0,0xc(%esp)   
                                 1a:   00                                              
                                 1b:   8b 44 24 0c             mov    0xc(%esp),%eax   
                                 1f:   ff d0                   call   *%eax            
                                 21:   b8 00 00 00 00          mov    $0x0,%eax        
                                 26:   c9                      leave                   
                                 27:   c3                      ret                     
文sub$0 x 10,%espはスタックに16バイトの空間を割り当て,pfはスタックの下部の4バイトアドレスを占有し,0 xc(%esp)は変数pfがスタックに割り当てられたアドレスである.
movl$0 x 0,0 xc(%esp)に注意すると、ここでは実際に関数アドレス0 x 0に変数pfが付与され、pfというメモリ変数の内容がeaxレジスタに付与され、関数fn()のコードがcall*%eaxによって呼び出され、この呼び出しは非常に理解しやすい.
次のコードも動作します.
void fn(){};
int main(){
    (*fn)();        call   0 <__Z2fnv>
}
ここでfn()は直接関数ポインタの構文を用いて呼び出され、コンパイラによって生成されたアセンブリは変数を用いず、直接関数アドレスでfn()が呼び出されたことに注意する.