Quel est le but du registre RBP dans x86 64 assembleur?

J'essaie donc d'apprendre un peu d'assemblage, parce que j'en ai besoin pour mon cours D'Architecture informatique. J'ai écrit quelques programmes, comme Imprimer la séquence de Fibonacci.

j'ai reconnu que chaque fois que j'écris un programme j'utilise ces 3 lignes (comme j'ai appris en comparant le code d'assemblage généré par gccC équivalent):

pushq   %rbp
movq    %rsp, %rbp
subq    , %rsp

j'ai 2 questions à ce sujet:

  1. tout d'abord, pourquoi j'utilise %rbp? N'est-il pas plus simple de utilisez %rsp, comme son contenu est déplacé à %rbp sur la 2ème ligne?
  2. Pourquoi dois-je soustraire quoi que ce soit de <!--4? Je veux dire, ce n'est pas toujours 16 (quand j'étais printfing ligne 7 ou 8 variables, alors je wold soustraire 24 ou 28

J'utilise Manjaro 64 bit sur une Machine virtuelle (4 Go de RAM), Processeur Intel 64 bit

22
demandé sur Peter Cordes 2017-01-28 20:29:23

2 réponses

rbp est le pointeur de cadre sur x86_64. Dans votre code généré, il obtient un instantané du pointeur de pile (rsp) de sorte que, lorsque des ajustements sont apportés à rsp(c'est-à-dire réserver de l'espace pour les variables locales ou pushles valeurs ing sur la pile), les variables locales et les paramètres de fonction sont encore accessibles à partir d'un décalage constant de rbp.

un grand nombre de compilateurs offrent l'omission de pointeur de trame comme option d'optimisation; cela rendra l'accès au Code d'assemblage généré variables relatives à rsp au lieu de cela et de libérer rbp comme autre registre général pour l'utilisation dans les fonctions.

dans le cas de GCC, que j'imagine que vous utilisez à partir de la syntaxe de l'assembleur AT&T, Ce commutateur est -fomit-frame-pointer. Essayez de compiler votre code avec ce commutateur et voyez quel code d'assemblage vous obtenez. Vous remarquerez probablement que lorsque vous accédez à des valeurs relatives à rsp au lieu de rbp, le décalage du pointeur varie tout au long de la fonction.

16
répondu Govind Parmar 2017-01-28 17:42:31

Linux utilise le système V ABI pour l'architecture x86-64 (AMD64); voir System V ABI at OSDev Wiki pour plus de détails.

cela signifie la pile pousse vers le bas; les adresses plus petites sont "plus hautes" dans la pile. Les fonctions C typiques sont compilées à

        pushq   %rbp        ; Save address of previous stack frame
        movq    %rsp, %rbp  ; Address of current stack frame
        subq    , %rsp   ; Reserve 16 bytes for local variables

        ; ... function ...

        movq    %rbp, %rsp  ; \ equivalent to the
        popq    %rbp        ; / 'leave' instruction
        ret

La quantité de mémoire réservée pour les variables locales est toujours un multiple de 16 octets, pour garder la pile alignée à 16 octets. Si aucun espace de pile n'est nécessaire pour les variables locales, il n'

(Notez que l'adresse de retour et le précédent %rbp poussé à la pile sont les deux 8 bytes de taille, 16 bytes au total.)

%rbp points de l'actuel cadre de pile, %rsp pointe vers le haut de la pile. Parce que le compilateur connaît la différence entre %rbp et %rsp a n'importe quel point de la fonction, il est libre d'utiliser l'un ou l'autre comme base pour les variables locales.

Un cadre de pile est juste le terrain de jeu de la fonction locale: la région de pile que la fonction courante utilise.

versions actuelles de GCC désactivent le cadre de la pile lorsque des optimisations sont utilisées. Cela a du sens, parce que pour les programmes écrits en C, les cadres de pile sont plus utiles pour le débogage, mais pas grand chose d'autre. (Vous pouvez utiliser, par exemple,-O2 -fno-omit-frame-pointer pour garder les cadres de pile tout en permettant des optimisations autrement, cependant.)

bien que le même ABI s'applique à tous les binaires, quelle que soit leur langue sont écrits en, certains autres langages ont besoin de cadres de pile pour "unwinding" (par exemple, pour "jeter des exceptions" à un ancêtre appelant de la fonction courante); c.-à-d. pour "unwind" cadres de pile qu'une ou plusieurs fonctions peuvent être avortées et le contrôle passé à une fonction ancêtre, sans laisser des trucs inutiles sur la pile.

Lors de la pile d'images sont omis -- -fomit-frame-pointer pour GCC--, la fonction implementation change essentiellement en

        subq    , %rsp    ; Re-align stack frame, and
                            ; reserve memory for local variables

        ; ... function ...

        addq    , %rsp
        ret

Parce qu'il n'y est pas cadre de pile (%rbp est utilisé à d'autres fins, et sa valeur n'est jamais poussée à la pile), chaque appel de fonction pousse seulement l'adresse de retour à la pile, qui est une quantité de 8 octets, donc nous devons soustraire 8 de %rsp pour garder un multiple de 16. (En général, la valeur soustraite de et ajouté à %rsp est un multiple Impair de 8.)

les paramètres de fonction sont typiquement passés dans les registres. Voir le lien ABI au début de cette réponse pour plus de détails, mais en bref, intégral les types et les pointeurs sont passés dans les registres %rdi,%rsi,%rdx,%rcx,%r8 et %r9, avec des arguments à virgule flottante dans le %xmm0%xmm7 registres.

Dans certains cas, vous verrez rep ret au lieu de rep. Ne pas confondre: le rep ret signifie exactement la même chose que ret;rep le préfixe, bien que normalement utilisé avec les instructions de chaîne (instructions répétées), ne fait rien lorsqu'il est appliqué à la ret instruction. C'est juste que certains prédicteurs de branche des processeurs AMD n'aiment pas sauter à un ret instruction, et la solution recommandée est d'utiliser un rep ret là à la place.

Enfin, j'ai omis zone rouge au-dessus du sommet de la pile (les 128 octets aux adresses inférieures à %rsp). C'est parce que ce n'est pas vraiment utile pour les fonctions typiques: dans le cas normal d'avoir-stack-frame, vous voudrez que votre contenu local soit dans le cadre de la pile, pour rendre le débogage possible. Dans le cas omit-stack-frame, les exigences d'alignement de la pile signifient déjà que nous devons soustraire 8 de %rsp, donc inclure la mémoire requise par les variables locales dans cette soustraction ne coûte rien.

22
répondu Nominal Animal 2018-01-02 21:32:02