web-dev-qa-db-fra.com

Quelle est l'utilisation de "Push% ebp; movl% esp,% ebp" générée par GCC pour x86?

Quel est l'effet de ces deux instructions sur le code d'assemblage généré par gcc pour les machines x86:

Push %ebp
movl %esp, %ebp
34
mahesh

l’explication de undind est la vérité littérale (malgré une erreur de direction mineure), mais n’explique pas pourquoi.

%ebp est le "pointeur de base" de votre cadre de pile. C'est le pointeur utilisé par le runtime C pour accéder aux variables et paramètres locaux de la pile. Voici quelques exemples de code de prologue de fonction générés par GCC (g ++ pour être précis) Commençons par la source C++.

// junk.c++
int addtwo(int a)
{
    int x = 2;

    return a + x;
}

Cela génère l'assembleur suivant.

.file   "junk.c++"
    .text
.globl _Z6addtwoi
    .type   _Z6addtwoi, @function
_Z6addtwoi:
.LFB2:
    pushl   %ebp
.LCFI0:
    movl    %esp, %ebp
.LCFI1:
    subl    $16, %esp
.LCFI2:
    movl    $2, -4(%ebp)
    movl    -4(%ebp), %edx
    movl    8(%ebp), %eax
    addl    %edx, %eax
    leave
    ret
.LFE2:
    .size   _Z6addtwoi, .-_Z6addtwoi
    .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
    .section    .note.GNU-stack,"",@progbits

Maintenant, pour expliquer ce code de prologue (tout ce qui précède .LCFI2:), d’abord:

  1. pushl %ebp stocke le cadre de pile de la fonction appelant sur la pile.
  2. movl %esp, %ebp prend le pointeur de pile actuel et l'utilise comme cadre pour la fonction appelée .
  3. subl $16, %esp laisse de la place pour les variables locales.

Maintenant, votre fonction est prête pour les affaires. Toutes les références avec un décalage négatif du registre %ebp% sont vos variables locales (x dans cet exemple). Toutes les références avec un décalage positif du registre %ebp% sont vos paramètres transmis.

Le dernier point d’intérêt est l’instruction leave, qui est une instruction assembleur x86 qui permet de restaurer le cadre de pile de la fonction appelante. Ceci est généralement optimisé dans les séquences plus rapides move %ebp %esp et pop %ebp% en code C. Cependant, à des fins d'illustration, je n'ai pas compilé avec aucune optimisation.

59

C'est le code typique que vous voyez au début d'une fonction.

Il enregistre le contenu du registre EBP sur la pile, puis stocke le contenu du pointeur de pile actuel dans EBP.

La pile est utilisée lors d’un appel de fonction pour stocker les arguments locaux. Mais dans la fonction, le pointeur de pile peut changer car des valeurs sont stockées dans la pile.

Si vous enregistrez la valeur d'origine de la pile, vous pouvez vous référer aux arguments stockés via le registre EBP, tout en utilisant (ajouter des valeurs à) la pile.

A la fin de la fonction, vous verrez probablement la commande

pop %ebp   ; restore original value 
ret        ; return 
9
Roalt
Push %ebp

Cela poussera le registre du pointeur de base 32 bits (étendu) sur la pile, c'est-à-dire que le pointeur de la pile (% esp) sera soustrait de quatre, puis la valeur de% ebp sera copiée à l'emplacement indiqué par le pointeur de la pile.

movl %esp, %ebp

Ceci copie le registre de pointeur de pile dans le registre de pointeur de base.

Le but de la copie du pointeur de pile sur le pointeur de base est de créer un cadre de pile, c’est-à-dire une zone de la pile où un sous-programme peut stocker des données locales. Le code dans le sous-programme utiliserait le pointeur de base pour référencer les données.

6
Guffa

Cela fait partie de ce qu'on appelle le prologue function .

Il enregistre le pointeur de base actuel à récupérer à la fin de la fonction et définit le nouveau PBP au début du nouveau cadre.

2
mgv

Je pense aussi qu’il est important de noter que souvent après Push %ebp et movl %esp, %ebp L’assemblée aura le Push %ebx ou le Push %edx. Ce sont des sauvegardes d’appelants des registres %ebx et %edx. À la fin de l'appel de routine, les registres seront restaurés avec leurs valeurs d'origine. 

Aussi - %ebx, %esi, %edi sont tous des registres de sauvegarde appelés. Donc, si vous voulez les écraser, vous devez d'abord les enregistrer, puis les restaurer.

1
Alex Spencer

Le morceau de code configure la pile pour votre programme.

En x86, les informations de pile sont conservées par deux registres.


    Base pointer (bp): Holds starting address of the stack
    Stack pointer (sp): Holds the address in which next value will be stored

Ces registres ont des noms différents selon les modes:

Base pointer           Stack pointer
 Mode réel 16 bits: bp sp 
 Mode protégé 32 bits: ebp (% ebp) esp (% esp) 
 Mode 64 bits: rbp rsp 
 </ Code>

Lorsque vous configurez une pile, le pointeur de pile et le pointeur de base obtiennent la même adresse au début. 

Maintenant pour expliquer votre code,


    Push %ebp

Ce code pousse l'adresse de la pile actuelle dans la pile afin que la fonction puisse "quitter" ou "revenir" correctement.


    movl %esp, %ebp

Ce code configure la pile pour votre fonction.

Pour plus d’informations, référez-vous à cette question .

J'espère que cette aide!

0
RainingComputers