GAS: explication de .cfi_def_cfa_offset

Je voudrais une explication pour les valeurs utilisées avec les directives .cfi_def_cfa_offset dans l’assembly généré par GCC. Je sais vaguement que les directives .cfi sont impliquées dans les trames d’appel et le déroulement de la stack, mais j’aimerais une explication plus détaillée des raisons pour lesquelles, par exemple, les valeurs 16 et 8 sont utilisées dans l’assemblage généré par GCC lors de la compilation du programme C suivant sur ma machine Ubuntu 64 bits.

Le programme C:

#include  int main(int argc, char** argv) { printf("%d", 0); return 0; } 

J’ai invoqué GCC sur le fichier source test.c comme suit: gcc -S -O3 test.c Je sais que -O3 permet une optimisation non standard, mais je voulais limiter la taille de l’assemblage généré par souci de concision.

L’assemblage généré:

  .file "test.c" .section .rodata.str1.1,"aMS",@progbits,1 .LC0: .ssortingng "%d" .text .p2align 4,,15 .globl main .type main, @function main: .LFB22: .cfi_startproc subq $8, %rsp .cfi_def_cfa_offset 16 xorl %edx, %edx movl $.LC0, %esi movl $1, %edi xorl %eax, %eax call __printf_chk xorl %eax, %eax addq $8, %rsp .cfi_def_cfa_offset 8 ret .cfi_endproc .LFE22: .size main, .-main .ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2" .section .note.GNU-stack,"",@progbits 

Pourquoi les valeurs 16 et 8 sont-elles utilisées pour les directives .cfi_def_cfa_offset dans l’assembly généré? Aussi, pourquoi le numéro 22 utilisé pour les étiquettes de début et de fin de fonction locale?

Comme l’indique la spécification DWARF dans la section 6.4:

[…] La trame d’appel est identifiée par une adresse sur la stack. Nous nous référons à cette adresse comme l’adresse du cadre canonique ou CFA. En règle générale, le CFA est défini comme étant la valeur du pointeur de stack sur le site d’appel dans la trame précédente (qui peut être différente de sa valeur à l’entrée de l’image actuelle).

main() est appelée ailleurs (dans le code de support d’exécution de libc C) et, au moment où l’instruction d’ call est exécutée, %rsp pointe vers le haut de la stack (l’adresse la plus basse). ), quoi qu’il en soit (exactement ce qu’il n’est pas important ici):

 : : ^ | whatever | <--- %rsp | increasing addresses +----------------+ | 

La valeur de %rsp à ce stade est la "valeur du pointeur de la stack sur le site d'appel", c'est-à-dire le CFA défini par la spécification.

Lorsque l'instruction d' call est exécutée, une adresse de retour de 64 bits (8 octets) est envoyée sur la stack:

 : : | whatever | <--- CFA +----------------+ | return address | <--- %rsp == CFA - 8 +----------------+ 

Maintenant, nous subq $8, %rsp le code main , qui exécute subq $8, %rsp pour réserver 8 octets subq $8, %rsp de stack pour lui-même:

 : : | whatever | <--- CFA +----------------+ | return address | +----------------+ | reserved space | <--- %rsp == CFA - 16 +----------------+ 

Le changement de pointeur de stack est déclaré dans les informations de débogage à l'aide de la directive .cfi_def_cfa_offset et vous pouvez voir que le CFA est maintenant à un décalage de 16 octets du pointeur de stack actuel.

À la fin de la fonction, l' addq $8, %rsp modifie à nouveau le pointeur de la stack. Une autre directive .cfi_def_cfa_offset est insérée pour indiquer que le CFA est maintenant décalé de seulement 8 octets par rapport au pointeur de la stack.

(Le nombre "22" dans les étiquettes est juste une valeur arbitraire. Le compilateur générera des noms d'étiquettes uniques en fonction de certains détails d'implémentation, tels que la numérotation interne des blocs de base.)

Je voudrais une explication pour les valeurs utilisées avec les directives .cfi_def_cfa_offset dans l’assembly généré par GCC.

Matthew a fourni une bonne explication. Voici la définition de la section 7.10 des directives de la FCI dans le manuel GAS:

.cfi_def_cfa_offset modifie une règle pour calculer CFA. Register rest le même, mais offset est nouveau. Notez que c’est le décalage absolu qui sera ajouté à un registre défini pour calculer l’adresse CFA.

Et .cfi_adjust_cfa_offset :

Identique à .cfi_def_cfa_offset mais offset est une valeur relative ajoutée / soustraite au décalage précédent.