2012-03-05 20 views
3

のx86アセンブリスタック予約

#include <stdio.h> 

int func() 
{ 
    printf("Hello World\n"); 
    return 0; 
} 

int main() 
{ 
    printf("Hello World\n"); 
    return 0; 
} 

この

は、32ビットアセンブリを対応しているこの単純なCプログラムを考えてみましょう

.file "a.c" 
     .section  .rodata 
    .LC0: 
     .string "Hello World" 
     .text 
    .globl func 
     .type func, @function 
    func: 
     pushl %ebp 
     movl %esp, %ebp 
     subl $24, %esp 
     movl $.LC0, (%esp) 
     call puts 
     movl $0, %eax 
     leave 
     ret 
     .size func, .-func 
    .globl main 
     .type main, @function 
    main: 
      pushl %ebp 
      movl %esp, %ebp 
      andl $-16, %esp 
      subl $16, %esp 
      movl $.LC0, (%esp) 
      call puts 
      movl $0, %eax 
      leave 
      ret 
      .size main, .-main 
      .ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3" 
      .section  .note.GNU-stack,"",@progbits 

なぜ文字列のためのgccの予備24バイトの "Hello World"関数 'func()'では同じ文字列のメイン関数の16バイトだけですか?

+0

これは文字列とは関係ありません。スタックにはロードされません。メイン関数のプロローグの$ 16はスタックポインタを整列させるためのものです。 andl命令に注意してください。 –

+0

ハンス、あなたはmainのandl命令について話しています。スタックポインタをページ境界に合わせるandl命令。私はサブ関数$ 16(%esp)をメイン関数&subl $ 24(%esp)のfuncで求めています – user1249669

答えて

0

コンパイラは両方の関数に16Bを割り当てようとしています(それがそれほど必要かどうかは疑問です)。

"main"では、単純に16Bを割り当ててputsを呼び出します。コールが呼び出される前に、スタックが0 mod 16にアライメントされていることに注意してください。これは、ABIでは必須です(スタックは常に呼び出し前に0 mod 16になるためです)。

funcでは、スタックは(復帰アドレスのために)12 mod 16に整列しています。次に、ebpを押して8 mod16にします。今度は、スタックに16Bを割り当てたい(mainと同様)が必要ですが、スタックをコールする前にスタックを0 mod 16バイトにしたいので、 8 + 16バイト(24)を減算します。