2017-03-31 10 views
6

は、ここで私は(x86用)整列スタックポインタを維持するために16バイトのローカル・バッファを宣言gccがなぜローカル用に余分なスペースを割り当てることがあるのですか?

#include <stdio.h>                

char func_with_ret() 
{ 
    return 1; 
} 
void func_1() 
{ 
    char buf[16]; 
    func_with_ret(); 
} 
void func_2() 
{ 
    char buf[16]; 
    getchar(); 
} 
int main() 
{ 
    func_1(); 
    func_2(); 
} 
  1. 私のコードです。
  2. 私は2つの関数 "func_1"、 "func_2"を書いていますが、それらはほぼ同じです - 16バイトのローカルバッファを割り当て、char戻り値とパラメータなしで関数を呼び出しますが、一方は自己定義で、もう一つはgetchar ()。
  3. 予期しない最適化動作を避けるため、gccパラメータ "-fno-stack-protector"(スタックにカナリアがないため)と "-O0"を使用してコンパイルします。

ここでは、func_1とfunc_2のgdbによる逆アセンブリコードを示します。 FUNC_1で

Dump of assembler code for function func_1: 
    0x08048427 <+0>:  push ebp 
    0x08048428 <+1>:  mov ebp,esp 
    0x0804842a <+3>:  sub esp,0x10 
    0x0804842d <+6>:  call 0x804841d <func_with_ret> 
    0x08048432 <+11>: leave 
    0x08048433 <+12>: ret 

Dump of assembler code for function func_2: 
    0x08048434 <+0>:  push ebp 
    0x08048435 <+1>:  mov ebp,esp 
    0x08048437 <+3>:  sub esp,0x18 
    0x0804843a <+6>:  call 0x80482f0 <[email protected]> 
    0x0804843f <+11>: leave 
    0x08048440 <+12>: ret 

、バッファが しかしfunc_2において、それは0x18の(24)バイトに割り当てられているが0x10(16)バイトに割り当てられている、なぜですか?


編集: は、バッファサイズが実際の両方で同じであることを把握し、それがどこから来るかわからないfunc_2で 奇妙な8バイトのスタックスペースがあります@Attie。

+1

関連:http://stackoverflow.com/questions/9862017/stack-allocation-why-the-extra-space – rsp

+0

はおそらくそれが実際その 'getchar関数()' 'を返すとは何かを持っています'func_with_ret()'は 'char'を返します。しかし、最終的に、なぜあなたは気にしますか? –

+0

私は両方の場合[ここ](https://godbolt.org/g/SUkHqw)で16を取得します。あなたのコンパイラは何ですか? – Arash

答えて

1

私は以下を参照してください、これを再現しようとしている:

x86-64(喜び)用にコンパイル:

$ gcc p.c -g -o p -O0 -fno-stack-protector 
$ objdump -d p 

p:  file format elf64-x86-64 

[...] 

0000000000400538 <func_1>: 
    400538:  55      push %rbp 
    400539:  48 89 e5    mov %rsp,%rbp 
    40053c:  48 83 ec 10    sub $0x10,%rsp 
    400540:  b8 00 00 00 00   mov $0x0,%eax 
    400545:  e8 e3 ff ff ff   callq 40052d <func_with_ret> 
    40054a:  c9      leaveq 
    40054b:  c3      retq 

000000000040054c <func_2>: 
    40054c:  55      push %rbp 
    40054d:  48 89 e5    mov %rsp,%rbp 
    400550:  48 83 ec 10    sub $0x10,%rsp 
    400554:  e8 c7 fe ff ff   callq 400420 <[email protected]> 
    400559:  c9      leaveq 
    40055a:  c3      retq 

i386(成功)のためのコンパイル:

$ gcc p.c -g -o p -O0 -fno-stack-protector -m32 
$ objdump -d p 

p:  file format elf32-i386 

[...] 

08048427 <func_1>: 
8048427:  55      push %ebp 
8048428:  89 e5     mov %esp,%ebp 
804842a:  83 ec 10    sub $0x10,%esp 
804842d:  e8 eb ff ff ff   call 804841d <func_with_ret> 
8048432:  c9      leave 
8048433:  c3      ret 

08048434 <func_2>: 
8048434:  55      push %ebp 
8048435:  89 e5     mov %esp,%ebp 
8048437:  83 ec 18    sub $0x18,%esp 
804843a:  e8 b1 fe ff ff   call 80482f0 <[email protected]> 
804843f:  c9      leave 
8048440:  c3      ret 

このdoesnの次のいずれかに関連しているようです:

  • getchar()はライブラリ関数なので、PLT(Procedure Linkage Table)を呼び出しています。あなたはしかし、増加した場合、関数の戻り値の型
  • バイナリ
  • ダイナミック/静的コンパイルに

内の関数の順序main()

  • のコールの注文に関連
  • バッファーのサイズを17に設定すると、スタックの使用率はそれぞれ32と40バイト(16バイトと24バイト)に増加します。違いは16バイトで、アライメントにはhereと答えています。

    func_2()と入力しても、スタックアライメントが8バイトずれているように見える理由はわかりません。


    あなたは15バイトのバッファ、およびシングルバイトの変数を持つようにfunc_1()func_2()を更新し、それらにデータを書き込む場合は、これらの項目は、スタックフレームのどこにいるか、そして、あなたが見ることができます:

    void func_1(void) { 
        char buf[15]; 
        char x; 
        buf[0] = 0xaa; 
        x = 0x55; 
        func_with_ret(); 
    } 
    
    void func_2(void) { 
        char buf[15]; 
        char x; 
        buf[0] = 0xaa; 
        x = 0x55; 
        getchar(); 
    } 
    
    08048434 <func_1>: 
    8048434:  55      push %ebp 
    8048435:  89 e5     mov %esp,%ebp 
    8048437:  83 ec 10    sub $0x10,%esp 
    804843a:  c6 45 f0 aa    movb $0xaa,-0x10(%ebp) 
    804843e:  c6 45 ff 55    movb $0x55,-0x1(%ebp) 
    8048442:  e8 d6 ff ff ff   call 804841d <func_with_ret> 
    8048447:  c9      leave 
    8048448:  c3      ret 
    
    08048449 <func_2>: 
    8048449:  55      push %ebp 
    804844a:  89 e5     mov %esp,%ebp 
    804844c:  83 ec 18    sub $0x18,%esp 
    804844f:  c6 45 e8 aa    movb $0xaa,-0x18(%ebp) 
    8048453:  c6 45 f7 55    movb $0x55,-0x9(%ebp) 
    8048457:  e8 94 fe ff ff   call 80482f0 <[email protected]> 
    804845c:  c9      leave 
    804845d:  c3      ret 
    
  • +0

    ありがとう!したがって、バッファサイズは両方とも同じに維持されますか?しかし、どこかのfunc_2のための8バイトのスタックスペースがあります... – poming

    関連する問題