Что делает GCC с моим стеком? - PullRequest
0 голосов
/ 09 ноября 2010

РЕДАКТИРОВАТЬ Настоящий вопрос в конце поста Я пытаюсь понять, как gcc управляет размером стека, но у меня есть вопрос, который я не нахожу.

Gcc делает что-то странное, когда я вызываю функцию в другой.Он выделяет дополнительные байты, и я не понимаю, для чего.

Вот самый простой код на C:

int f(){
    int i =12;
    return 0;
}


int main(void){
    f();
    return 0;
}

, а затем дисбаланс f (), который создает gdb:

0x08048386 <+0>:     push   %ebp
0x08048387 <+1>:     mov    %esp,%ebp
0x08048389 <+3>:     sub    $0x10,%esp <- this part
0x0804838c <+6>:     movl   $0xc,-0x4(%ebp)
0x08048393 <+13>:    mov    $0x0,%eax
0x08048398 <+18>:    leave  
0x08048399 <+19>:    ret  

Здесь хорошо, я понимаю.gcc делает 16-байтовый стек выравнивания, так как i является целым числом (то есть 4 байта) gcc выделяет 16 байтов в стеке для i.

Но как только я вызываю функцию в f (), я не получаю то, чтоGCC делает.Вот новый код C:

int g(int i){
    i=12;
    return i;
}

int f(){
    int i =12;
    g(i);
    return 0;
}


int main(void){
    f();
    return 0;
}

А затем f () пропадает:

0x08048386 <+0>:     push   %ebp
0x08048387 <+1>:     mov    %esp,%ebp
0x08048389 <+3>:     sub    $0x14,%esp <- Here is my understanding
0x0804838c <+6>:     movl   $0xc,-0x4(%ebp)
0x08048393 <+13>:    mov    -0x4(%ebp),%eax
0x08048396 <+16>:    mov    %eax,(%esp)
0x08048399 <+19>:    call   0x8048374 <g>
0x0804839e <+24>:    mov    $0x0,%eax
0x080483a3 <+29>:    leave  
0x080483a4 <+30>:    ret

Затем gcc выделяет 4 дополнительных байта, тогда как изменений больше нет, чем f ()Вызов g ().

И это может быть хуже, когда я играю с большим количеством функций.

Итак, у кого-нибудь из вас есть идея, для чего нужны эти дополнительные байты и какова политика выделения стека в gcc?

Заранее спасибо.

РЕДАКТИРОВАТЬ: реальный вопрос

Хорошо, извините, я написал вопрос слишком быстро, на самом деле все в порядке с подпунктом 0x14%ESP Я действительно понимаю, с этим фрагментом кода:

int f(){
    char i[5];
    char j[5];
    i[4]=0;
    j[4]=0;
    strcpy(i,j);
    return 0;
}


int main(void){
    f();
    return 0;
}

А затем f () 's disass:

0x080483a4 <+0>:     push   %ebp
0x080483a5 <+1>:     mov    %esp,%ebp
0x080483a7 <+3>:     sub    $0x28,%esp
0x080483aa <+6>:     movb   $0x0,-0x9(%ebp)
0x080483ae <+10>:    movb   $0x0,-0xe(%ebp)
0x080483b2 <+14>:    lea    -0x12(%ebp),%eax
0x080483b5 <+17>:    mov    %eax,0x4(%esp)
0x080483b9 <+21>:    lea    -0xd(%ebp),%eax
0x080483bc <+24>:    mov    %eax,(%esp)
0x080483bf <+27>:    call   0x80482d8 <strcpy@plt>
0x080483c4 <+32>:    mov    $0x0,%eax
0x080483c9 <+37>:    leave  
0x080483ca <+38>:    ret

Стек выглядит примерно так:

[oldip] [oldebp] [Extra (8B)] [Arrays (10B)] [Перегруппировать стек (14B)] [Argument1 (4B)] [Argument2 (4B)]

Здесь мы видим, что 8дополнительные байты находятся между сохраненным ebp и локальными переменными.Итак, вот мое понимание.

Извините за слишком быструю публикацию, и все же спасибо за ваш быстрый ответ.

Ответы [ 2 ]

0 голосов
/ 09 ноября 2010

Я бы подумал, что в первом случае 4 байта соответствуют одному параметру, необходимому при вызове g ().и во втором случае два 4-байтовых слова, необходимых для двух параметров при вызове strcpy ().вызовите фиктивную функцию с тремя параметрами и посмотрите, не изменится ли она на 12 байтов.

0 голосов
/ 09 ноября 2010
0x08048386 <+0>:     push   %ebp
0x08048387 <+1>:     mov    %esp,%ebp
0x08048389 <+3>:     sub    $0x14,%esp <- include 0x10 bytes for stack alignment and 4 byte for 1 parameter
0x0804838c <+6>:     movl   $0xc,-0x4(%ebp)
0x08048393 <+13>:    mov    -0x4(%ebp),%eax
0x08048396 <+16>:    mov    %eax,(%esp)
0x08048399 <+19>:    call   0x8048374 <g>
0x0804839e <+24>:    mov    $0x0,%eax
0x080483a3 <+29>:    leave  
0x080483a4 <+30>:    ret

Как вы можете видеть, он выделяет 16 байтов, включая i и выравнивание стека, плюс 4 байта для одного параметра, стек будет выглядеть следующим образом.

00 7f 7c 13              --> return from call address
00 00 00 00              --> this one for parameter when call g(i)  --> low address
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 0C ---> i       (ignore about edian)        --> high address 
...