2010-11-09 31 views
0

EDIT La vraie question est à la fin de la poste J'essaie de comprendre comment gcc gère la taille de la pile mais j'ai quelques questions que je ne trouve pas la réponse. Gcc fait quelque chose de bizarre quand j'appelle une fonction dans une autre. Il alloue des octets supplémentaires et je ne comprends pas pour quoi.Que fait gcc avec ma pile?

Voici le code C jamais simpliest:

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


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

puis la disass de f() qui gdb produit:

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 

Ici ok j'undestand. gcc fait une pile d'alignement de 16 octets comme je l'ai un int (donc 4 octets) gcc alloue 16 octets sur la pile pour i. Mais dès que j'appelle une fonction dans f(), je ne comprends pas ce que fait gcc. Voici le nouveau code C:

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

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


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

Et puis le f() disass:

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 

Ensuite gcc alloue 4 octets supplémentaires alors qu'il n'y a pas plus de changements que f() appelle g().

Et cela peut être pire quand je joue avec plus de fonctions.

Donc, vous avez une idée de ce que sont ces octets supplémentaires et quelle est la politique d'allocation de pile de gcc?

Merci d'avance.

EDIT: vraie question

Ok désolé j'ai écrit la question trop vite en fait, il est ok avec le sous 0x14% esp ma compréhension réelle est avec ce morceau de code:

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; 
} 

et puis 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 <[email protected]> 
0x080483c4 <+32>: mov $0x0,%eax 
0x080483c9 <+37>: leave 
0x080483ca <+38>: ret 

L'aspect pile comme quelque chose comme ça:

[oldip] [oldebp] [extra (8B)] [Les tableaux (10B)] [Réorganiser pile (14B)] [Argument1 (4B)] [Argument2 (4B)]

Ici, nous voyons que 8 des octets supplémentaires viennent entre les ebp enregistrées et les variables locales . Donc, voici vraiment ma compréhension.

Désolé d'avoir posté trop vite et toujours merci pour votre réponse rapide .

+1

f est défini exactement de la même manière dans les deux listes de codes. Voulez-vous dire mettre un code différent dans le premier? – Heatsink

+1

Collecte de la valeur renvoyée que vous supprimez? –

Répondre

0
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 

comme vous pouvez le voir, il allouer 16 octets inclus i et l'alignement de la pile, plus 4 octets pour un paramètre, la pile ressemblera à ceci.

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 
0

Je pense que dans le premier cas, les 4 octets sont pour le paramètre nécessaire lors de l'appel de g(). et dans le second cas, deux mots de 4 octets sont nécessaires pour les deux paramètres lors de l'appel de strcpy(). appeler une fonction fictive avec trois paramètres et voir si elle change à 12 octets.

+0

Je ne pense pas parce que les arguments sont stocker après les deux tableaux, puis les 8 octets supplémentaires sont avant ce tableau: [oldeip] [oldebp] [Dummy 8bytes] [tableau (16bytes)] [Dummy 8bytes] [arguments (8bits)] – poulecaca

+0

hmm, d'accord, juste une théorie –