2010-11-24 14 views
1

J'attribue 12 chaînes de caractères sur la pile, ou de façon équivalente, il s'agit de 12 octets. Dissemblable avec gdb (sous Linux) révèle que pour allouer de l'espace pour la chaîne sur la pile, esp est déplacé par -24 (en bas de la pile).Allocation de chaîne sur la pile

push %ebp 
mov %esp,%ebp 
sub $0x18,%esp 

Pourquoi est-il déplacé par 24 (0x18)?

+0

Il serait plus facile de répondre si vous montriez le code C –

+0

Je suppose que c'est difficile à dire sans voir votre code d'entrée. –

+0

F() {tableau [12] ...}, l'assemblage ci-dessus est l'appel à sa fonction – newprint

Répondre

6

Certains d'entre eux pourraient être l'espace pour les paramètres sortants, si votre fonction en appelle d'autres; certains d'entre eux pourraient être un espace temporaire pour les valeurs déversées dans les registres; certains d'entre eux pourraient être rembourrés. Cela dépendra beaucoup de la version du compilateur et des indicateurs d'optimisation.

est ici un code non-sens simple illustration:

extern int foo(int a, int b); 

int bar(int c) 
{ 
    char s[12]; 

    s[0] = foo(c, 123); 
    return 456; 
} 

Ici, il est compilé avec aucune optimisation utilisant gcc 4.3.2 sur une machine Debian Lenny:

bar: 
    pushl %ebp 
    movl %esp, %ebp 
    subl $24, %esp 
    movl $123, 4(%esp) 
    movl 8(%ebp), %eax 
    movl %eax, (%esp) 
    call foo 
    movb %al, -12(%ebp) 
    movl $456, %eax 
    leave 
    ret 

Comme votre code, il est l'allocation 24 octets. Voici ce qu'ils sont utilisés pour:

 
    Stack while running bar() 
    :       : 
    +-------------------------+ 
    | incoming parameter: c | 8(%ebp) 
    +-------------------------+   --- 
    | return address   | 4(%ebp) ^
    +-------------------------+    | 
    | old %ebp    | (%ebp)  | 
    +-------------------------+    | bar()'s stack 
    | s[8]..s[11]    | -4(%ebp) | frame: 32 bytes 
    +-------------------------+    | 
    | s[4]..s[7]    | -8(%ebp) | 
    +-------------------------+    | 
    | s[0]..s[3]    | -12(%ebp) | 
    +-------------------------+    |  Stack while running foo() 
    | (unused)    | 8(%esp)  | :       : 
    +-------------------------+    | +-------------------------+ 
    | outgoing parameter: 123 | 4(%esp)  | | incoming parameter: b | 
    +-------------------------+    | +-------------------------+ 
    | outgoing parameter: c | (%esp)  v | incoming parameter: a | 
    +-------------------------+   --- +-------------------------+ 
               | return address   | 
               +-------------------------+ 
               | old %ebp    | 
               +-------------------------+ 
               : locals for foo()  : 

Un peu d'expérience montrera que si s[] augmente, il mangera dans l'espace inutilisé; par exemple. si elle est de 13 octets, la trame de la pile a la même taille, mais s[] démarrera un octet plus tôt (à -13(%ebp)) - jusqu'à 16 octets, où toute la pile allouée sera réellement utilisée. Si s est déclaré comme s[17], le compilateur allouera 40 octets de pile au lieu de 24.

Cela est dû au fait que le compilateur conserve la taille totale du cadre de la pile (tout à gauche du diagramme ci-dessus, à l'exception du paramètre, qui est vraiment en bas de la pile de l'appelant) arrondi à un multiple de 16 octets. (Voir la documentation gcc pour l'option -mpreferred-stack-boundary.)

+0

WOW! J'ai besoin de digérer un peu. Y at-il un programme pour générer de tels diagrammes cool? – newprint

+0

Je pense que je l'ai eu. Je m'attendais à ce que mon tableau commence aussi à -24, car 24 octets ont été alloués. D'après votre diagramme, j'avais totalement tort, ça commence à -12. Donc, quand le tableau est poussé sur la pile, il commencera -12 et avancera vers le haut (je vois la raison pour laquelle array est "en arrière, c'est petit endian) – newprint

+0

Eh bien, l'espace réservé aux paramètres doit être en bas fin de l'espace alloué pour l'appel de la fonction Le compilateur arrive à choisir de remplir l'espace restant avec le remplissage à l'extrémité inférieure et le tableau au sommet (mais c'est probablement un choix assez arbitraire). "-' s [0] 'est à l'adresse la plus basse et' s [11] 'est au plus haut - je viens de dessiner mon diagramme avec l'adresse la plus basse en bas! (Endianness se rapporte à l'ordre dans lequel les octets de une valeur multi-octets telle qu'un entier de 32 bits est stockée, votre tableau est juste une séquence d'octets.) –

2

Parce que d'autres éléments que votre chaîne sont stockés sur la pile, tels que d'autres variables locales ou temporaires. Lorsque vous avez des expressions compliquées, les magasins de compilation stockent parfois les résultats intermédiaires de ces expressions en mémoire sur la pile (en particulier lorsque l'optimisation est désactivée), même si elles ne correspondent pas à des variables locales explicites.