2016-10-31 5 views
2

私はちょうど最近のように、私は初心者です、私はかなり簡単で基本的なプログラムを書いてきたと私は奇妙な(私に)気づいたように、私のアセンブリの旅を始めた。なぜ "rsp"を使ってC++関数を呼び出す必要がありますか?

バイナリ

エントリポイントで111で終わるテーブル内の数値のカウントを与えるプログラム:

#include <iostream> 
#include <cstdlib> 

extern "C" auto _start(void *, void *)->void; 

auto print_msg(char *msg) { 
    std::cout << msg; 
} 

auto print_int(uint64_t val) { 
    std::cout << val; 
} 

auto main()->int { 
    _start(print_int, print_msg); 
    std::cout << std::endl; 
    system("pause"); 
} 

アセンブリ:

.const 
_tab dw 65535, 61951, 61949, 61925, 61927, 61734, 61735, 61728 
_LENGTH = ($ - _tab)/2 
_msg_1 db 'There are ', 0 
_msg_2 db ' numbers ending with 111 in binary!', 0 

.code 
_start proc 
     push  r15 
     push  r14 
     sub  rsp, 32 + 16 
     mov  r14, rcx 
     mov  r15, rdx 
     xor  rcx, rcx 
     xor  r9, r9 
     lea  r8, _tab 
_LOOP: movzx rax, word ptr [r8] 
     and  rax, 111b 
     cmp  rax, 111b 
     jz  _INC 
     jmp  _END_IF 
_INC: inc  rcx 
_END_IF: inc  r9 
     add  r8, 2 
     cmp  r9, _LENGTH 
     jne  _LOOP 
     mov  [rsp + 32], rcx 
     lea  rcx, _msg_1 
     call  r15 
     mov  rcx, [rsp + 32] 

     sub  rsp, 8 
     call  r14 
     add  rsp, 8 

     lea  rcx, _msg_2 
     call  r15 
     add  rsp, 32 + 16 
     pop  r14 
     pop  r15 
     ret 
_start endp 

end 

私がコメントする場合」 sub rsp、8 "、" add rsp、8 "を呼び出すと、プログラムはすぐにクラッシュします私はなぜそれが起こるのか知りたいのですが、また、 "mov rspx32"、 "rcx"、 "mov rcx rspx32"を "push rcx"と " popのrcx "の場合、出力はゴミになります。私はそれについても興味があります

+1

関数 '_start'を呼び出さないでください。これはエントリポイントのデフォルトの名前です(少なくともLinuxでは)。独自の '_start'を定義するプログラムは、標準のCRTスタートアップコードをリンクせず、' _start'は返すことのできる関数でもありません。それは単なるエントリーポイントです。 TL:DR: '_start'は多くの読者にとって混乱している関数名です。 –

答えて

4

Windows x86-64呼び出し規約では、CALL命令の前にRSPの16Bアライメントが必要です。これは、関数呼び出しの周囲のsub rsp,8について説明しています。

また、呼び出された関数の使用のために32Bのシャドウスペースが予約されている必要があります。これがsub rsp, 32 + 16の動作です。

これらを一緒に組み合わせることは賢明で、sub rsp, 32 + 16 + 8は機能のエントリにしてから、エピローグまでRSPを混乱させないでください。 mov [rsp + 32], rcxのオフセットを変更することがありますが、それが重要かどうかはわかりません。私はあなたの全体のコードを読んでみることはしませんでした。

呼び出される関数がシャドウ領域を使用する理由は、データがシャドウ領域にあるため、CALLの周りをプッシュ/ポップすると、なぜ文字化けした出力が得られるのかを説明します。


大会リンクを呼び出す/ ABIのためタグのwikiを参照してください。

関連する問題