1

プラットフォームはx86_64Windows7です。

Cのソースコードは次のとおりです。

#include<windows.h>
int main(void){
    asm("int3");
    CreateWindowEx(0,NULL,NULL,0,5,6,7,8,NULL,NULL,NULL,NULL);
    return(0);
}

これは、次のアセンブリにコンパイルされます。

push rbp
mov rbp,rsp
sub rsp,60h
int3
mov qword[rsp+58h],0
mov qword[rsp+50h],0
mov qword[rsp+48h],0
mov qword[rsp+40h],0
mov qword[rsp+38h],8
mov qword[rsp+30h],7
mov qword[rsp+28h],6
mov qword[rsp+20h],5
mov r9d,0
mov r8d,0
mov edx,0
mov ecx,0
call CreateWindowEx
mov eax,0
add rsp,60h
pop rbp
ret

そして概念的には、これはさまざまな実行ポイントでのスタックに対して私が持っているものです(アドレスは任意です):

90 -rsp-

90 old rbp
88 -rsp-

90 old rbp
88 -rsp- -rbp-

90 old rbp
88 -rbp- (never used?)
80 (rsp+58h)
78 (rsp+50h)
70 (rsp+48h)
68 (rsp+40h)
60 (rsp+38h)
58 (rsp+30h)
50 (rsp+28h)
48 (rsp+20h)
40 (shadow)
38 (shadow)
30 (shadow)
28 -rsp- (shadow) (will contain call instruction's return pointer...)

ご覧のとおり、Cプログラムのコンパイル済み出力によると、スタックに問題があります。まず、使用されない8バイトがあり、シャドウスペースの8バイトは、リターンポインタの呼び出し命令によって上書きされます。8バイト上にシフトすれば問題ないので、すべてが本来より8バイト下にシフトされているようです。ただし、API呼び出しは期待どおりに機能しますが、これはMicrosoftの呼び出し規約の実装を見落としているだけですか?

4

1 に答える 1

3

何かがスタックにプッシュされると、新しいアイテムはrsp命令の開始時にポイントしている場所に移動しません-rsp新しいアイテムを格納する前にデクリメントされます(つまり、rspポイントするスタックの場所が使用中です)。

したがって、rsp ==0x90その関数を開始するときに、古いrbpものはアドレスにあります0x88(そしてrbp、そのアドレスを指すようになります)。

次にrsp == 0x28call命令が実行されると、リターンアドレスはアドレス0x20ではなくアドレスに配置されます0x28

于 2012-09-02T09:43:06.647 に答える