Patricia Renault UPMC 2005/2006 UE MAREP Cours 7 : La pile d’exécution (Fonctions avec variables locales - Passage des arguments par valeur ou par adresse) Patricia Renault UPMC 2005/2006
Plan Rappels Représentation des variables locales d’une fonction Passage des arguments par valeur ou par adresse
Plan Rappels Représentation des variables locales d’une fonction Fonction sans variable locale, passage des arguments par valeur Représentation des variables locales d’une fonction Passage des arguments par valeur ou par adresse
Convention La fonction appelante La fonction appelée Empile les arguments (en commençant par le dernier) Effectue l’appel à l’appelé Obtient le résultat dans $2 Dépile les arguments La fonction appelée Empile $31 Empile les registres dont elle se sert dans son traitement Effectue son traitement et place le résultat dans $2 Restaure les valeurs des registres qu’elle avait sauvegardées Dépile $31 et les registres utilisés par la fonction appelée Retourne à l’appelant prologue épilogue
Plan Rappels Représentation des variables locales d’une fonction Définition Convention Exemple Cas général Passage des arguments par valeur ou par adresse
Définition Une variable locale est une variable dont la portée est limitée à une fonction (variable définie à l’intérieur d’une fonction) Exemple : int fadd(int a, int b){ int i, c = 0; for (i=a; i<b; i++){ c = c + i; } return c;
Convention Les variables locales d’une fonction appelée sont systématiquement allouées sur la pile d’exécution, par la fonction appelée, dans son prologue. La zone mémoire attribuée aux variables locales est détruite par la fonction appelée dans son épilogue. Cette réservation est parfois superflue, mais par soucis de simplicité et de régularité de représentation des appels de fonction, nous réaliserons systématiquement cette allocation.
Convention La fonction appelante (aucune modification) Empile les arguments (en commençant par le dernier) Effectue l’appel à l’appelé Obtient le résultat dans $2 Dépile les arguments
Convention La fonction appelée Empile $31 Empile les registres dont elle se sert dans son traitement Réserve la place sur la pile pour représenter ses variables locales Effectue son traitement et place le résultat dans $2 Restaure les valeurs des registres qu’elle avait sauvegardées Libère l’espace de la pile réservé aux variables locales Dépile $31 et les registres utilisés par la fonction appelée Retourne à l’appelant
Exemple int x = 1, y = 4, t1; int fadd(int a, int b){ int i, c = 0; for (i=a; i<b; i++){ c = c + i;} return c; } void main(){ t1 = fadd(x,y); printf(”%d\n”, t1); exit(0);
Exemple .data x : .word 1 y : .word 4 t1 : .word .stack 256 #256 octets pour la pile .text __start : lui $5, x>>16 ori $5, $5, x & 0xFFFF lw $5, ($5) # x dans $5 lui $6, y>>16 ori $6, $6, y & 0xFFFF lw $6, ($6) # y dans $6
Exemple addiu $29, $29, -8 # empile les 2 arguments sw $6, 4($29) # passage de y sw $5, ($29) # passage de x jal fadd # appel de fadd addiu $29, $29, 8 # depile les 2 arguments lui $7, t1 >> 16 ori $7, $7, t1 & 0xFFFF sw $2, ($7) # met fadd(x,y) ds mot d@ t1 ori $4, $2, 0 # affichage ori $2, $0, 1 syscall
Exemple ori $2, $0, 10 # fin syscall fadd : # prologue addiu $29, $29, -28 #$31 + 4 reg + 2 v. loc sw $31, 24($29) sw $5, 20($29) sw $6, 16($29) sw $7, 12($29) sw $8, 8($29) lw $5, 28($29) # $5 contient a lw $6, 32($29) # $6 contient b
Exemple # corps de la fonction fadd #$5 : a, $6 : b, $7 : i, $8 : c xor $8, $8, $8 ori $7, $5, 0 fboucle : slt $9, $7, $6 # 1 si i<b beq $9, $0, fin_fadd add $8, $8, $7 addi $7, $7, 1 j fboucle
Exemple fin_fadd : ori $2, $8, 0 # resultat dans le registre 2 # epilogue lw $31, 24($29) lw $5, 20($29) lw $6, 16($29) lw $7, 12($29) lw $8, 8($29) addiu $29, $29, 28 jr $31
Exemple i ($29) c 4($29) $8 8($29) $7 12($29) $6 16($29) $5 20($29) @ret ($31) 24($29) a 28($29) b 32($29) ////////////// Variables locales de fadd Empilements par fadd Empilements par main
Cas général f appelle une fonction g ayant na arguments. g utilise nr registres pour réaliser le traitement. La fonction g déclare nv variables locales. On nomme : RAi le registre contenant l’argument i (dans l’appelant f ) RRj le registre persistant numéro j (dans l’appelé g) RPk le registre contenant le paramètre k (dans l’appelé g)
Cas général Code de f : # inchangé … addiu $29, $29, -4 * na sw $Ana-1, 4*(na-1)($29) sw $Ana-2, 4*(na-2)($29) sw $A0, 0($29) jal g addiu $29, $29, 4 * na
Cas général Code de g : g : # prologue addiu $29, $29, -4*(nr + nv +1) sw $31, 4* (nr + nv) ($29)# sauvegarde reg sw $Rnr, 4* (nr + nv – 1) ($29) … sw $R0, 4* nv($29) lw $P0, 4*(nr + nv +1)($29)# récup des arg lw $P1, 4*(nr + nv +2)($29) lw $Pna-1, 4*(nr + nv + na)($29)
Cas général # … traitement de la fonction # $2 contient le résultat de la fonction # epilogue lw $R0, 4* nv($29) … lw $Rnr, 4 * (nr + nv – 1) ($29) lw $31, 4 * (nr + nv) ($29) jr $31
Cas général Zone des variables locales V(nv-1) $29 après prologue fonction appelée … V(0) Zone de sauvegarde des registres R(nr-1) R(0) @ret ($31) Zone des arguments A(0) $29 avant et après appel fonction appelée A(na-1) ////////////// $29 initial et final Empilements par la fonction appelée Empilements par la fonction appelante
Plan Rappels Représentation des variables locales d’une fonction Passage des arguments par valeur ou par adresse Limites du passage par valeur Solution : le passage par adresse Exemple
Limites du passage par valeur Avec un passage par valeur : Lors de l’appel d’une fonction, les arguments sont transmis à la fonction appelée par recopie dans la pile. Ceci implique que les modifications effectuées dans la fonction appelée sur les arguments ne sont pas répercutées à la fonction appelante. C’est ce qu’on appelle un passage par valeur. Problème : La recopie des variables volumineuses peut nécessiter du temps. Le résultat retourné par la fonction appelante est dans le registre 2. Une fonction peut vouloir retourner plusieurs valeurs.
Solution : le passage par adresse Pour éviter la recopie des variables volumineuses dans la pile et permettre à la fonction appelée de modifier des arguments il faut passer les arguments par adresse. L’adresse de la case mémoire où se trouve l’argument à modifier est placée dans la pile par la fonction appelante. La fonction appelée peut alors avec cette adresse modifier le contenu de cette case mémoire. Pour réaliser un passage d’argument par adresse, il faut déclarer l’argument dans le segment data.
Exemple int faddinc(int a, int* p){ *p = *p + 1; return (a + *p); } int x = 2, y = 3, z = 4; int t1; void main(){ t1 = faddinc(x,&y); printf("%d\n",t1); exit(0); Valeur de la variable Adresse de la variable
Exemple .data x : .word 2 y : .word 3 t1 : .word .stack 256 #256 octets pour la pile .text __start : lui $5, x>>16 ori $5, $5, x & 0xFFFF lw $5, ($5) # x dans $5 lui $6, y>>16 ori $6, $6, y & 0xFFFF # @ de y dans $6
Exemple addiu $29, $29, -8 # empile les 2 arguments sw $6, 4($29) # passage de l’@ de y sw $5, ($29) # passage de x jal faddinc addiu $29, $29, 8 lui $7, t1 >> 16 ori $7, $7, t1 & 0xFFFF sw $2, ($7) # met faddinc(x,&y) mot d@ t1 ori $4, $2, 0 # affichage ori $2, $0, 1 syscall
Exemple ori $2, $0, 10 # fin syscall faddinc : # prologue addiu $29, $29, -16 #$31 + 3 registres sw $31, 12($29) sw $5, 8($29) sw $6, 4($29) sw $7, ($29) lw $5, 16($29) # $5 contient a lw $6, 20($29) # $6 contient @ de p
Exemple #$5 : a, $6 : @ de p, $7 : valeur de p lw $7, ($6) addi $7, $7, 1 sw $7,($6) add $2, $7, $5 lw $31, 12($29) # epilogue lw $5, 8($29) lw $6, 4($29) lw $7, ($29) addiu $29, $29, 16 jr $31
Exemple $7 ($29) $6 4($29) $5 8($29) @ret ($31) 12($29) a 16($29) @ p 20($29) ////////////// Empilements par faddinc Empilements par main