La mémoire
La mémoire physique de l'ordinateur
La mémoire de l'ordinateur est assimilable, en première approximation
à un long tableau continu. La largeur de ce tableau s'exprime en "bits".
En général, les cette taille comporte des subdivisions. En effet, pour une
taille de 32bits, par exemple, un octet n'etant codé que sur 8bits, il est
nécessaire, afin de ne pas perdre trop d'espace, de pouvoir stocker 4 octets
différents par case de 32 bits et donc accéder de manière indépendante à ces 4
subdivisions.
Un bus 32bits est en général découpé en subdivisions de 8 et 16 bits.
Chaque subdivision (octet) est numérotée. Cette numérotation correspond à une
adresse mémoire.
Espace mémoire des programmes C
Cette dernière vision des choses ne s'applique pas à la réalité virtuelle d'un processus.
En effet, il est fréquent de voir des processus utiliser plus de mémoire que la quantité
de RAM physique réellement disponible. Dans ce dernier cas, l'application utilise une partie
de la mémoire RAM, mais aussi d'autres formes telle que le swap.
Le système et les différents composants matériels (en particulier la "Memory Management Unit",
MMU ou unité de gestion de la mémoire) se chargent d'agréger les différentes ressources (RAM,
swap, disque dur, ...) et de faire croire aux processus que la mémoire est un vaste tableau
homogène et contigu.
Les mécanismes rendant possible cette illusion sont assez complexes dépassent de loin le cadre
de ce document, mais ce sujet est largement
couvert
1.
Il est cependant nécessaire de noter que les cases du "tableau-mémoire" ne sont pas
réllement présentes (i.e. pointent réellement vers des zones de mémoire physique réelle)
que lorsque celles-ci sont réellement utilisées.
Pour chaque processus, cette zone contigüe s'étale de
0x00000000 à
0xFFFFFFFF.
La zone inférieure à la zone de chargement du segment text du programme est réservée et
ne peut être accédée en écriture.
La zone supérieure à la valeur de la macro
PAGE_OFFSET
est réservée pour le noyau (mapping noyau des zones de mémoire du processus).
Cet espace mémoire est rempli selon certaines règles dépendantes des sytèmes et des
architectures matérielles.
Figure 1 : utilisation de la mémoire pour chaque processus.
Zone programme
Tout d'abord la zone de "
programme", découpée en plusieurs segments dont :
- Le segment texte (.text) contient le code machine du programme.
- Le segment bss (.bss) contient les données non initialisées (variables globales du C). BSS signifie "Block Stating Symbol".
- Le segment data (.data) contient les données initialisées du programmes (constantes globales).
Le tas (heap)
Ensuite, vient le
tas (heap). C'est la mémoire allouée dynamiquement
avec les fonctions de type malloc(). La croissance de cette zone s'effectue vers les
adresses hautes. L'adresse de base du tas est donnée par la fonction sbrk(0) avant toute
allocation ou par brk(0).
Le mémoire libre
Vient la zone de
mémoire libre", ou mémoire non allouée. Elle est
consommée par le tas.
La réservation d'une zone suppémentaire se fait avec la fonction sbrk(taillesupp) ou
taillesup est la taille de la zone à réserver.
Zone de liens dynamiques
Après cette zone de mémoire libre, une
partie de la mémoire est réservée pour les
bibliothèques dynamiques (links), chargées soit lors du chargement de l'exécutable
quand les bibliothèques ont été référencées lors de la phase d'édition de liens (symboles
nécessaires à la compilation), soit pendant l'exéction du programme et par le programme
lui même par l'appel aux fonctions
dlopen() et
dlsym() (programmation de greffons, chargement de modules ...).
La pile (stack)
Enfin, la dernière zone de l'espace utilisateur est la
pile. La pile commence,
à l'inverse des autres zones, à l'adresse la plus haute (soit théoriquement
PAGE_OFFSET-1). La pile croit donc vers les
adresses basses.
La pile se compose de boites ou cadres (frames). Chacune de ces boites correspont à une
procédure ou fonction. La fonction
main() sera
la boite 1 (seconde sur la pile). Si
main()
appelle une fonction "
toto()", alors, lorsque
le programme passera dans
toto(), une boite
numérotée 2 sera placée sur la pile, au "dessus" de la boite numérotée 1 de
main().
A la sortie de la fonction toto(), la boite numéro 2 sera détruite (dépilée/modification
de la topographie ou mapping de la mémoire virtelle).
Chaque boite contient les variables locales à la procédure (i.e. définie sur la pile),
l'adresse de retour de la procédure, une sauvegarde des paramères passée en entrée à la
procédure, voire aussi une copie de tout ou partie de la zone de registres du microprocesseur.
Une boite, ou frame, n'est donc valide que tant que l'on ne sort pas de la fonction à
laquelle elle est associée.
Il n'est donc possible d'utiliser un pointeur sur une zone de mémoire réservée sur la
pile que dans la fonction où cette mémoire est réservée et les sous fonctions appelées
par cette fonction.
Des la sortie d'une fonction, la zone la frame associée à cette fonction est éliminée
de la carte de la mémoire virtuelle. La zone occupée par l'ancienne frame se retrouve
donc contenir des données aléatoires.
En corrolaires :
La pile est réservée statiquement. Il est impossible de changer dynamiquement sa taille.
Une pile est alloué localement :
- pour le programme (variable globale non statique, ou définie comme externe),
- pour le fichier en cours (variable globale statique),
- pour la fonction en cours (variables définies en début de fonction).
La pile représente la proportion de la mémoire de travail utilisée temporairement
pour un traitement particulier.
% cat frameshow.c
#include
int function3(int a, int b, int c, int d) {
int i_3 = 0x30303030;
printf("in function3
");
return 0x3F3F3F3F;
}
int function2(int a, int b, int c, int d) {
int i_2 = 0x20202020;
printf("in function2
");
function3(0xCCCCCCC1, 0xCCCCCCC2, 0xCCCCCCC3, 0xCCCCCCC4);
return 0x2F2F2F2F;
}
int function1(int a, int b, int c, int d) {
int i_1 = 0x10101010;
printf("in function1
");
function2(0xBBBBBBB1, 0xBBBBBBB2, 0xBBBBBBB3, 0xBBBBBBB4);
return 0x1F1F1F1F;
}
int final(int a, int b) {
int i_final = 0x0FF00FF0;
return i_final;
}
int
main() {
int i_main = 0x12345678;
printf("in main
");
function1(0xAAAAAAA1, 0xAAAAAAA2, 0xAAAAAAA3, 0xAAAAAAA4);
final(0xDDDDDDD1, 0xDDDDDDD2);
return 0;
}
% cc -g frameshow.c -o frameshow
% dis frameshow
**** DISASSEMBLER ****
disassembly for frameshow
section .text
_start()
106b8: bc 10 20 00 clr %fp
106bc: e0 03 a0 40 ld [%sp + 64], %l0
106c0: 13 00 00 83 sethi %hi(0x20c00), %o1
106c4: e0 22 60 54 st %l0, [%o1 + 0x54]
106c8: a2 03 a0 44 add %sp, 68, %l1
106cc: 13 00 00 83 sethi %hi(0x20c00), %o1
106d0: e2 22 60 50 st %l1, [%o1 + 0x50]
106d4: 13 00 00 83 sethi %hi(0x20c00), %o1
106d8: e2 22 60 44 st %l1, [%o1 + 0x44]
106dc: a5 2c 20 02 sll %l0, 2, %l2
106e0: a4 04 a0 04 add %l2, 4, %l2
106e4: a4 04 40 12 add %l1, %l2, %l2
106e8: 27 00 00 83 sethi %hi(0x20c00), %l3
106ec: e8 04 e0 38 ld [%l3 + 0x38], %l4
106f0: 80 a5 20 00 cmp %l4, 0
106f4: 12 80 00 03 bne 0x10700
106f8: 01 00 00 00 nop
106fc: e4 24 e0 38 st %l2, [%l3 + 56]
10700: 2b 00 00 00 sethi %hi(__fsr_init_value), %l5
10704: aa 15 60 00 or %l5, __fsr_init_value, %l5 ! __fsr_init_value
10708: 80 90 00 15 orcc %g0, %l5, %g0
1070c: 02 80 00 12 be 0x10754
10710: 01 00 00 00 nop
10714: ad 2d 60 02 sll %l5, 2, %l6
10718: ae 0d a3 00 and %l6, 768, %l7
1071c: ac 0d 60 3f and %l5, 63, %l6
10720: ac 15 80 17 or %l6, %l7, %l6
10724: ab 2d a0 16 sll %l6, 22, %l5
10728: 29 00 00 83 sethi %hi(0x20c00), %l4
1072c: a8 15 20 3c or %l4, 0x3c, %l4 ! __crt_scratch
10730: c1 2d 00 00 st %fsr, [%l4]
10734: ec 05 00 00 ld [%l4], %l6
10738: ae 20 00 17 sub %g0, %l7, %l7
1073c: af 3d e0 1f sra %l7, 31, %l7
10740: af 2d e0 1e sll %l7, 30, %l7
10744: ac 2d 80 17 andn %l6, %l7, %l6
10748: ac 15 80 15 or %l6, %l5, %l6
1074c: ec 25 00 00 st %l6, [%l4]
10750: c1 0d 00 00 ld [%l4], %fsr
10754: 9c 23 a0 20 sub %sp, 32, %sp
10758: 80 90 00 01 orcc %g0, %g1, %g0
1075c: 02 80 00 04 be 0x1076c
10760: 90 10 00 01 mov %g1, %o0
10764: 40 00 40 f1 call atexit
10768: 01 00 00 00 nop
1076c: 11 00 00 42 sethi %hi(0x10800), %o0
10770: 40 00 40 ee call atexit
10774: 90 12 22 7c or %o0, 636, %o0
10778: 11 00 00 83 sethi %hi(0x20c00), %o0
1077c: d0 02 20 48 ld [%o0 + 0x48], %o0
10780: 80 90 00 08 orcc %g0, %o0, %g0
10784: 12 80 00 09 bne 0x107a8
10788: 01 00 00 00 nop
1078c: 11 00 00 83 sethi %hi(0x20c00), %o0
10790: d0 02 20 4c ld [%o0 + 0x4c], %o0
10794: 80 90 00 08 orcc %g0, %o0, %g0
10798: 02 80 00 04 be 0x107a8
1079c: 01 00 00 00 nop
107a0: 40 00 40 e2 call atexit
107a4: 01 00 00 00 nop
107a8: 40 00 00 b2 call _init
107ac: 01 00 00 00 nop
107b0: 90 10 00 10 mov %l0, %o0
107b4: 92 10 00 11 mov %l1, %o1
107b8: 94 10 00 12 mov %l2, %o2
107bc: 96 10 00 13 mov %l3, %o3
107c0: 40 00 00 88 call main
107c4: 01 00 00 00 nop
107c8: 40 00 40 db call exit
107cc: 01 00 00 00 nop
107d0: 40 00 40 dc call _exit
107d4: 01 00 00 00 nop
107d8: 00 01 00 00 unimp 0x10000
107dc: 00 01 00 00 unimp 0x10000
107e0: 00 01 00 00 unimp 0x10000
107e4: 00 01 00 00 unimp 0x10000
function3()
107e8: 9d e3 bf 98 save %sp, -104, %sp
107ec: f6 27 a0 50 st %i3, [%fp + 80]
107f0: f4 27 a0 4c st %i2, [%fp + 76]
107f4: f2 27 a0 48 st %i1, [%fp + 72]
107f8: f0 27 a0 44 st %i0, [%fp + 68]
107fc: 21 0c 0c 0c sethi %hi(0x30303000), %l0
10800: a0 14 20 30 or %l0, 0x30, %l0 ! 0x30303030
10804: e0 27 bf f8 st %l0, [%fp - 8]
10808: 21 00 00 42 sethi %hi(0x10800), %l0
1080c: a0 14 22 b8 or %l0, 0x2b8, %l0 ! 0x10ab8
10810: 40 00 40 cf call printf
10814: 90 14 00 00 or %l0, %g0, %o0
10818: 21 0f cf cf sethi %hi(0x3f3f3c00), %l0
1081c: a0 14 23 3f or %l0, 0x33f, %l0 ! 0x3f3f3f3f
10820: 10 80 00 04 ba 0x10830
10824: e0 27 bf fc st %l0, [%fp - 4]
10828: 10 80 00 02 ba 0x10830
1082c: 01 00 00 00 nop
10830: e0 07 bf fc ld [%fp - 4], %l0
10834: b0 14 00 00 or %l0, %g0, %i0
10838: 81 c7 e0 08 ret
1083c: 81 e8 00 00 restore
10840: 00 01 00 00 unimp 0x10000
10844: 00 01 00 00 unimp 0x10000
10848: 00 01 00 00 unimp 0x10000
1084c: 00 01 00 00 unimp 0x10000
function2()
10850: 9d e3 bf 98 save %sp, -104, %sp
10854: f6 27 a0 50 st %i3, [%fp + 80]
10858: f4 27 a0 4c st %i2, [%fp + 76]
1085c: f2 27 a0 48 st %i1, [%fp + 72]
10860: f0 27 a0 44 st %i0, [%fp + 68]
10864: 21 08 08 08 sethi %hi(0x20202000), %l0
10868: a0 14 20 20 or %l0, 0x20, %l0 ! 0x20202020
1086c: e0 27 bf f8 st %l0, [%fp - 8]
10870: 21 00 00 42 sethi %hi(0x10800), %l0
10874: a0 14 22 c8 or %l0, 0x2c8, %l0 ! 0x10ac8
10878: 40 00 40 b5 call printf
1087c: 90 14 00 00 or %l0, %g0, %o0
10880: 21 0c cc cc sethi %hi(0x33333000), %l0
10884: a0 1c 3c c1 xor %l0, -831, %l0
10888: 23 0c cc cc sethi %hi(0x33333000), %l1
1088c: a2 1c 7c c2 xor %l1, -830, %l1
10890: 25 0c cc cc sethi %hi(0x33333000), %l2
10894: a4 1c bc c3 xor %l2, -829, %l2
10898: 27 0c cc cc sethi %hi(0x33333000), %l3
1089c: a6 1c fc c4 xor %l3, -828, %l3
108a0: 90 14 00 00 or %l0, %g0, %o0
108a4: 92 14 40 00 or %l1, %g0, %o1
108a8: 94 14 80 00 or %l2, %g0, %o2
108ac: 7f ff ff cf call function3
108b0: 96 14 c0 00 or %l3, %g0, %o3
108b4: 21 0b cb cb sethi %hi(0x2f2f2c00), %l0
108b8: a0 14 23 2f or %l0, 0x32f, %l0 ! 0x2f2f2f2f
108bc: 10 80 00 04 ba 0x108cc
108c0: e0 27 bf fc st %l0, [%fp - 4]
108c4: 10 80 00 02 ba 0x108cc
108c8: 01 00 00 00 nop
108cc: e0 07 bf fc ld [%fp - 4], %l0
108d0: b0 14 00 00 or %l0, %g0, %i0
108d4: 81 c7 e0 08 ret
108d8: 81 e8 00 00 restore
108dc: 00 01 00 00 unimp 0x10000
108e0: 00 01 00 00 unimp 0x10000
108e4: 00 01 00 00 unimp 0x10000
108e8: 00 01 00 00 unimp 0x10000
108ec: 00 01 00 00 unimp 0x10000
function1()
108f0: 9d e3 bf 98 save %sp, -104, %sp
108f4: f6 27 a0 50 st %i3, [%fp + 80]
108f8: f4 27 a0 4c st %i2, [%fp + 76]
108fc: f2 27 a0 48 st %i1, [%fp + 72]
10900: f0 27 a0 44 st %i0, [%fp + 68]
10904: 21 04 04 04 sethi %hi(0x10101000), %l0
10908: a0 14 20 10 or %l0, 0x10, %l0 ! 0x10101010
1090c: e0 27 bf f8 st %l0, [%fp - 8]
10910: 21 00 00 42 sethi %hi(0x10800), %l0
10914: a0 14 22 d8 or %l0, 0x2d8, %l0 ! 0x10ad8
10918: 40 00 40 8d call printf
1091c: 90 14 00 00 or %l0, %g0, %o0
10920: 21 11 11 11 sethi %hi(0x44444400), %l0
10924: a0 1c 3f b1 xor %l0, -79, %l0
10928: 23 11 11 11 sethi %hi(0x44444400), %l1
1092c: a2 1c 7f b2 xor %l1, -78, %l1
10930: 25 11 11 11 sethi %hi(0x44444400), %l2
10934: a4 1c bf b3 xor %l2, -77, %l2
10938: 27 11 11 11 sethi %hi(0x44444400), %l3
1093c: a6 1c ff b4 xor %l3, -76, %l3
10940: 90 14 00 00 or %l0, %g0, %o0
10944: 92 14 40 00 or %l1, %g0, %o1
10948: 94 14 80 00 or %l2, %g0, %o2
1094c: 7f ff ff c1 call function2
10950: 96 14 c0 00 or %l3, %g0, %o3
10954: 21 07 c7 c7 sethi %hi(0x1f1f1c00), %l0
10958: a0 14 23 1f or %l0, 0x31f, %l0 ! 0x1f1f1f1f
1095c: 10 80 00 04 ba 0x1096c
10960: e0 27 bf fc st %l0, [%fp - 4]
10964: 10 80 00 02 ba 0x1096c
10968: 01 00 00 00 nop
1096c: e0 07 bf fc ld [%fp - 4], %l0
10970: b0 14 00 00 or %l0, %g0, %i0
10974: 81 c7 e0 08 ret
10978: 81 e8 00 00 restore
1097c: 00 01 00 00 unimp 0x10000
10980: 00 01 00 00 unimp 0x10000
10984: 00 01 00 00 unimp 0x10000
10988: 00 01 00 00 unimp 0x10000
1098c: 00 01 00 00 unimp 0x10000
final()
10990: 9d e3 bf 98 save %sp, -104, %sp
10994: f2 27 a0 48 st %i1, [%fp + 72]
10998: f0 27 a0 44 st %i0, [%fp + 68]
1099c: 21 03 fc 03 sethi %hi(0xff00c00), %l0
109a0: a0 14 23 f0 or %l0, 0x3f0, %l0 ! 0xff00ff0
109a4: e0 27 bf f8 st %l0, [%fp - 8]
109a8: e0 07 bf f8 ld [%fp - 8], %l0
109ac: 10 80 00 04 ba 0x109bc
109b0: e0 27 bf fc st %l0, [%fp - 4]
109b4: 10 80 00 02 ba 0x109bc
109b8: 01 00 00 00 nop
109bc: e0 07 bf fc ld [%fp - 4], %l0
109c0: b0 14 00 00 or %l0, %g0, %i0
109c4: 81 c7 e0 08 ret
109c8: 81 e8 00 00 restore
109cc: 00 01 00 00 unimp 0x10000
109d0: 00 01 00 00 unimp 0x10000
109d4: 00 01 00 00 unimp 0x10000
109d8: 00 01 00 00 unimp 0x10000
109dc: 00 01 00 00 unimp 0x10000
main()
109e0: 9d e3 bf 98 save %sp, -104, %sp
109e4: 21 04 8d 15 sethi %hi(0x12345400), %l0
109e8: a0 14 22 78 or %l0, 0x278, %l0 ! 0x12345678
109ec: e0 27 bf f8 st %l0, [%fp - 8]
109f0: 21 00 00 42 sethi %hi(0x10800), %l0
109f4: a0 14 22 e8 or %l0, 0x2e8, %l0 ! 0x10ae8
109f8: 40 00 40 55 call printf
109fc: 90 14 00 00 or %l0, %g0, %o0
10a00: 21 15 55 55 sethi %hi(0x55555400), %l0
10a04: a0 1c 3e a1 xor %l0, -351, %l0
10a08: 23 15 55 55 sethi %hi(0x55555400), %l1
10a0c: a2 1c 7e a2 xor %l1, -350, %l1
10a10: 25 15 55 55 sethi %hi(0x55555400), %l2
10a14: a4 1c be a3 xor %l2, -349, %l2
10a18: 27 15 55 55 sethi %hi(0x55555400), %l3
10a1c: a6 1c fe a4 xor %l3, -348, %l3
10a20: 90 14 00 00 or %l0, %g0, %o0
10a24: 92 14 40 00 or %l1, %g0, %o1
10a28: 94 14 80 00 or %l2, %g0, %o2
10a2c: 7f ff ff b1 call function1
10a30: 96 14 c0 00 or %l3, %g0, %o3
10a34: 21 08 88 88 sethi %hi(0x22222000), %l0
10a38: a0 1c 3d d1 xor %l0, -559, %l0
10a3c: 23 08 88 88 sethi %hi(0x22222000), %l1
10a40: a2 1c 7d d2 xor %l1, -558, %l1
10a44: 90 14 00 00 or %l0, %g0, %o0
10a48: 7f ff ff d2 call final
10a4c: 92 14 40 00 or %l1, %g0, %o1
10a50: 10 80 00 04 ba 0x10a60
10a54: c0 27 bf fc st %g0, [%fp - 4]
10a58: 10 80 00 02 ba 0x10a60
10a5c: 01 00 00 00 nop
10a60: e0 07 bf fc ld [%fp - 4], %l0
10a64: b0 14 00 00 or %l0, %g0, %i0
10a68: 81 c7 e0 08 ret
10a6c: 81 e8 00 00 restore
section .init
_init()
10a70: 9d e3 bf a0 save %sp, -96, %sp
10a74: 81 c7 e0 08 ret
10a78: 81 e8 00 00 restore
section .fini
_fini()
10a7c: 9d e3 bf a0 save %sp, -96, %sp
10a80: 81 c7 e0 08 ret
10a84: 81 e8 00 00 restore
% dbx frameshow
Reading frameshow
Reading ld.so.1
Reading libc.so.1
Reading libdl.so.1
Reading libc_psr.so.1
dbx> alias P="print -f0x%x"
dbx> print main
main = &main() at 0x109e0
dbx> print function1
function1 = &function1(int a, int b, int c, int d) at 0x108f0
dbx> print function2
function2 = &function2(int a, int b, int c, int d) at 0x10850
dbx> print function3
function3 = &function3(int a, int b, int c, int d) at 0x107e8
dbx> stop in main
(2) stop in main
dbx> run
Running: frameshow
(process id 28873)
stopped in main at line 31 in file "frameshow.c"
31 int i_main = 0x12345678;
dbx> next
stopped in main at line 32 in file "frameshow.c"
32 printf("in main
");
dbx> P $sp
$sp = 0xffbef3e0
dbx> P $fp
$fp = 0xffbef448
dbx> ex $sp, $fp
0xffbef3e0:
0x12345678 0x00000000 0x00000000 0x00000000
0xffbef3f0:
0x00000000 0x00000000 0x00000000 0xff3dc890
0xffbef400:
0x00000001 0xffbef4ac 0xffbef4b4 0x00020c00
0xffbef410:
0x00000000 0x00000000 0xffbef448 0x000107c0
0xffbef420:
0x00000000 0x00000000 0x00000003 0xffbef4ac
0xffbef430:
0x00000004 0xffbef4b4 0x00000005 0xffbef5fc
0xffbef440:
0x12345678 0x00000000 0x00000001
dbx> regs
current frame: [1]
g0-g3 0x00000000 0xff319c04 0x00000000 0x00000000
g4-g7 0x00000000 0x00000000 0x00000000 0x00000000
o0-o3 0x00000000 0xff3420d8 0xff33e5d8 0xffffffff
o4-o7 0x000222e8 0xff29bc20 0xffbef3e0 0xff29bc20
l0-l3 0x12345678 0x00000000 0x00000000 0x00000000
l4-l7 0x00000000 0x00000000 0x00000000 0xff3dc890
i0-i3 0x00000001 0xffbef4ac 0xffbef4b4 0x00020c00
i4-i7 0x00000000 0x00000000 0xffbef448 0x000107c0
y 0x00000000
ccr 0x00000000
pc 0x000109f0:main+0x10 sethi %hi(0x10800), %l0
npc 0x000109f4:main+0x14 or %l0, 0x2e8, %l0
dbx> next
stopped in main at line 33 in file "frameshow.c"
33 function1(0xAAAAAAA1, 0xAAAAAAA2, 0xAAAAAAA3, 0xAAAAAAA4);
dbx> step
stopped in function1 at line 18 in file "frameshow.c"
18 int i_1 = 0x10101010;
dbx> next
stopped in function1 at line 19 in file "frameshow.c"
19 printf("in function1
");
dbx> next
stopped in function1 at line 20 in file "frameshow.c"
20 function2(0xBBBBBBB1, 0xBBBBBBB2, 0xBBBBBBB3, 0xBBBBBBB4);
dbx> P $sp
$sp = 0xffbef378
dbx> P $fp
$fp = 0xffbef3e0
dbx> ex $sp, 0xffbef448
0xffbef378:
0x00010ad8 0x00000000 0x00000000 0x00000000
0xffbef388:
0x00000000 0x00000000 0x00000000 0x00000000
0xffbef398:
0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 input parameters
0xffbef3a8:
0x000222e8 0xff29bc20 0xffbef3e0 0x00010a2c previous stack end and
return address in main
0xffbef3b8:
0xffbef3e0 0x000109f8 0x00000000 0x00000000
0xffbef3c8:
0x00000000 0x00000000 0x00000000 0xff29bc20
0xffbef3d8:
0x10101010 0x000109f8 0xaaaaaaa1 0xaaaaaaa2 parameters passed
0xffbef3e8:
0xaaaaaaa3 0xaaaaaaa4 0x00000000 0x00000000 function1
0xffbef3f8:
0x00000000 0xff3dc890 0x00000001 0xffbef4ac
0xffbef408:
0xffbef4b4 0x00020c00 0x00000000 0x00000000
0xffbef418:
0xffbef448 0x000107c0 0x00000000 0xaaaaaaa1
0xffbef428:
0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8
0xffbef438:
0xff29bc20 0xffbef5fc 0x12345678 0x00000000 value of i_main on stack
0xffbef448:
0x00000001
dbx> regs
current frame: [1]
g0-g3 0x00000000 0x0000000a 0x00000000 0x00000000
g4-g7 0x00000000 0x00000000 0x00000000 0x00000000
o0-o3 0x0000000d 0xff340284 0xff343a54 0x00000000
o4-o7 0x00000000 0x00000000 0xffbef378 0x00010918
l0-l3 0x00010ad8 0x00000000 0x00000000 0x00000000
l4-l7 0x00000000 0x00000000 0x00000000 0x00000000
i0-i3 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4
i4-i7 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a2c
y 0x00000000
ccr 0x00000099
pc 0x00010920:function1+0x30 sethi %hi(0x44444400), %l0
npc 0x00010924:function1+0x34 xor %l0, -0x4f, %l0
dbx> step
stopped in function2 at line 11 in file "frameshow.c"
11 int i_2 = 0x20202020;
dbx> next
stopped in function2 at line 12 in file "frameshow.c"
12 printf("in function2
");
dbx> next
stopped in function2 at line 13 in file "frameshow.c"
13 function3(0xCCCCCCC1, 0xCCCCCCC2, 0xCCCCCCC3, 0xCCCCCCC4);
dbx> P $sp
$sp = 0xffbef310
dbx> P $fp
$fp = 0xffbef378
dbx> ex $sp, 0xffbef448
0xffbef310:
0x00010ac8 0x00000000 0x00000000 0x00000000
0xffbef320:
0x00000000 0x00000000 0x00000000 0x00000000
0xffbef330:
0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4
0xffbef340:
0x00000000 0x00000000 0xffbef378 0x0001094c
0xffbef350:
0xffbef5fc 0x00000000 0x00000000 0x00000000
0xffbef360:
0x00000000 0x00000000 0x00000000 0x00000000
0xffbef370:
0x20202020 0x00000000 0xbbbbbbb1 0xbbbbbbb2
0xffbef380:
0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000
0xffbef390:
0x00000000 0x00000000 0xaaaaaaa1 0xaaaaaaa2
0xffbef3a0:
0xaaaaaaa3 0xaaaaaaa4 0x000222e8 0xff29bc20
0xffbef3b0:
0xffbef3e0 0x00010a2c 0xffbef3e0 0xbbbbbbb1
0xffbef3c0:
0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4 0x00000000
0xffbef3d0:
0x00000000 0xff29bc20 0x10101010 0x000109f8
0xffbef3e0:
0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4
0xffbef3f0:
0x00000000 0x00000000 0x00000000 0xff3dc890
0xffbef400:
0x00000001 0xffbef4ac 0xffbef4b4 0x00020c00
0xffbef410:
0x00000000 0x00000000 0xffbef448 0x000107c0
0xffbef420:
0x00000000 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3
0xffbef430:
0xaaaaaaa4 0x000222e8 0xff29bc20 0xffbef5fc
0xffbef440:
0x12345678 0x00000000 0x00000001
dbx> regs
current frame: [1]
g0-g3 0x00000000 0x0000000a 0x00000000 0x00000000
g4-g7 0x00000000 0x00000000 0x00000000 0x00000000
o0-o3 0x0000000d 0xff340284 0xff343a54 0x00000000
o4-o7 0x00000000 0x00000000 0xffbef310 0x00010878
l0-l3 0x00010ac8 0x00000000 0x00000000 0x00000000
l4-l7 0x00000000 0x00000000 0x00000000 0x00000000
i0-i3 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4
i4-i7 0x00000000 0x00000000 0xffbef378 0x0001094c
y 0x00000000
ccr 0x00000099
pc 0x00010880:function2+0x30 sethi %hi(0x33333000), %l0
npc 0x00010884:function2+0x34 xor %l0, -0x33f, %l0
dbx> step
stopped in function3 at line 5 in file "frameshow.c"
5 int i_3 = 0x30303030;
dbx> next
stopped in function3 at line 6 in file "frameshow.c"
6 printf("in function3
");
dbx> next
stopped in function3 at line 7 in file "frameshow.c"
7 return 0x3F3F3F3F;
dbx> P $sp
$sp = 0xffbef2a8
dbx> P $fp
$fp = 0xffbef310
dbx> ex $sp, 0xffbef448
0xffbef2a8:
0x00010ab8 0x00000000 0x00000000 0x00000000
0xffbef2b8:
0x00000000 0x00000000 0x00000000 0x00000000
0xffbef2c8:
0xccccccc1 0xccccccc2 0xccccccc3 0xccccccc4
0xffbef2d8:
0x00000000 0x00000000 0xffbef310 0x000108ac
0xffbef2e8:
0x00000000 0x00000000 0x00000000 0x00000000
0xffbef2f8:
0x00000000 0x00000000 0x00000000 0x00000000
0xffbef308:
0x30303030 0x00000000 0xccccccc1 0xccccccc2
0xffbef318:
0xccccccc3 0xccccccc4 0x00000000 0x00000000
0xffbef328:
0x00000000 0x00000000 0xbbbbbbb1 0xbbbbbbb2
0xffbef338:
0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000
0xffbef348:
0xffbef378 0x0001094c 0xffbef5fc 0xccccccc1
0xffbef358:
0xccccccc2 0xccccccc3 0xccccccc4 0x00000000
0xffbef368:
0x00000000 0x00000000 0x20202020 0x00000000
0xffbef378:
0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4
0xffbef388:
0x00000000 0x00000000 0x00000000 0x00000000
0xffbef398:
0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4
0xffbef3a8:
0x000222e8 0xff29bc20 0xffbef3e0 0x00010a2c
0xffbef3b8:
0xffbef3e0 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3
0xffbef3c8:
0xbbbbbbb4 0x00000000 0x00000000 0xff29bc20
0xffbef3d8:
0x10101010 0x000109f8 0xaaaaaaa1 0xaaaaaaa2
0xffbef3e8:
0xaaaaaaa3 0xaaaaaaa4 0x00000000 0x00000000
0xffbef3f8:
0x00000000 0xff3dc890 0x00000001 0xffbef4ac
0xffbef408:
0xffbef4b4 0x00020c00 0x00000000 0x00000000
0xffbef418:
0xffbef448 0x000107c0 0x00000000 0xaaaaaaa1
0xffbef428:
0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8
0xffbef438:
0xff29bc20 0xffbef5fc 0x12345678 0x00000000
0xffbef448:
0x00000001
dbx> regs
current frame: [1]
g0-g3 0x00000000 0x0000000a 0x00000000 0x00000000
g4-g7 0x00000000 0x00000000 0x00000000 0x00000000
o0-o3 0x0000000d 0xff340284 0xff343a54 0x00000000
o4-o7 0x00000000 0x00000000 0xffbef2a8 0x00010810
l0-l3 0x00010ab8 0x00000000 0x00000000 0x00000000
l4-l7 0x00000000 0x00000000 0x00000000 0x00000000
i0-i3 0xccccccc1 0xccccccc2 0xccccccc3 0xccccccc4
i4-i7 0x00000000 0x00000000 0xffbef310 0x000108ac
y 0x00000000
ccr 0x00000099
pc 0x00010818:function3+0x30 sethi %hi(0x3f3f3c00), %l0
npc 0x0001081c:function3+0x34 or %l0, 0x33f, %l0
dbx> next
stopped in function3 at line 8 in file "frameshow.c"
8 }
dbx> next
stopped in function2 at line 14 in file "frameshow.c"
14 return 0x2F2F2F2F;
dbx> P $sp
$sp = 0xffbef310
dbx> P $fp
$fp = 0xffbef378
dbx> ex 0xffbef2a8, 0xffbef448
0xffbef2a8: 0x3f3f3f3f 0x00000000 0x00000000 0x00000000
0xffbef2b8: 0x00000000 0x00000000 0x00000000 0x00000000
0xffbef2c8: 0x3f3f3f3f 0xccccccc2 0xccccccc3 0xccccccc4
0xffbef2d8: 0x00000000 0x00000000 0xffbef310 0x000108ac
0xffbef2e8: 0x00000000 0x00000000 0x00000000 0x00000000
0xffbef2f8: 0x00000000 0x00000000 0x00000000 0x00000000
0xffbef308: 0x30303030 0x3f3f3f3f
0xccccccc1 0xccccccc2
0xffbef318:
0xccccccc3 0xccccccc4 0x00000000 0x00000000
0xffbef328:
0x00000000 0x00000000 0xbbbbbbb1 0xbbbbbbb2
0xffbef338:
0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000
0xffbef348:
0xffbef378 0x0001094c 0xffbef5fc 0xccccccc1
0xffbef358:
0xccccccc2 0xccccccc3 0xccccccc4 0x00000000
0xffbef368:
0x00000000 0x00000000 0x20202020 0x00000000
0xffbef378:
0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4
0xffbef388:
0x00000000 0x00000000 0x00000000 0x00000000
0xffbef398:
0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4
0xffbef3a8:
0x000222e8 0xff29bc20 0xffbef3e0 0x00010a2c
0xffbef3b8:
0xffbef3e0 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3
0xffbef3c8:
0xbbbbbbb4 0x00000000 0x00000000 0xff29bc20
0xffbef3d8:
0x10101010 0x000109f8 0xaaaaaaa1 0xaaaaaaa2
0xffbef3e8:
0xaaaaaaa3 0xaaaaaaa4 0x00000000 0x00000000
0xffbef3f8:
0x00000000 0xff3dc890 0x00000001 0xffbef4ac
0xffbef408:
0xffbef4b4 0x00020c00 0x00000000 0x00000000
0xffbef418:
0xffbef448 0x000107c0 0x00000000 0xaaaaaaa1
0xffbef428:
0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8
0xffbef438:
0xff29bc20 0xffbef5fc 0x12345678 0x00000000
0xffbef448:
0x00000001
dbx> regs
current frame: [1]
g0-g3 0x00000000 0x0000000a 0x00000000 0x00000000
g4-g7 0x00000000 0x00000000 0x00000000 0x00000000
o0-o3 0x3f3f3f3f 0xccccccc2 0xccccccc3 0xccccccc4
o4-o7 0x00000000 0x00000000 0xffbef310 0x000108ac
l0-l3 0xccccccc1 0xccccccc2 0xccccccc3 0xccccccc4
l4-l7 0x00000000 0x00000000 0x00000000 0x00000000
i0-i3 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4
i4-i7 0x00000000 0x00000000 0xffbef378 0x0001094c
y 0x00000000
ccr 0x00000099
pc 0x000108b4:function2+0x64 sethi %hi(0x2f2f2c00), %l0
npc 0x000108b8:function2+0x68 or %l0, 0x32f, %l0
dbx> next
stopped in function2 at line 15 in file "frameshow.c"
15 }
dbx> next
stopped in function1 at line 21 in file "frameshow.c"
21 return 0x1F1F1F1F;
dbx> P $sp
$sp = 0xffbef378
dbx> P $fp
$fp = 0xffbef3e0
dbx> ex 0xffbef2a8, 0xffbef448
0xffbef2a8: 0x3f3f3f3f 0x00000000 0x00000000 0x00000000
0xffbef2b8: 0x00000000 0x00000000 0x00000000 0x00000000
0xffbef2c8: 0x3f3f3f3f 0xccccccc2 0xccccccc3 0xccccccc4
0xffbef2d8: 0x00000000 0x00000000 0xffbef310 0x000108ac
0xffbef2e8: 0x00000000 0x00000000 0x00000000 0x00000000
0xffbef2f8: 0x00000000 0x00000000 0x00000000 0x00000000
0xffbef308: 0x30303030 0x3f3f3f3f 0x2f2f2f2f 0xccccccc2
0xffbef318: 0xccccccc3 0xccccccc4 0x00000000 0x00000000
0xffbef328: 0x00000000 0x00000000 0x2f2f2f2f 0xbbbbbbb2
0xffbef338: 0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000
0xffbef348: 0xffbef378 0x0001094c 0xffbef5fc 0xccccccc1
0xffbef358: 0xccccccc2 0xccccccc3 0xccccccc4 0x00000000
0xffbef368: 0x00000000 0x00000000 0x20202020 0x2f2f2f2f
0xffbef378:
0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4
0xffbef388:
0x00000000 0x00000000 0x00000000 0x00000000
0xffbef398:
0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4
0xffbef3a8:
0x000222e8 0xff29bc20 0xffbef3e0 0x00010a2c
0xffbef3b8:
0xffbef3e0 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3
0xffbef3c8:
0xbbbbbbb4 0x00000000 0x00000000 0xff29bc20
0xffbef3d8:
0x10101010 0x000109f8 0xaaaaaaa1 0xaaaaaaa2
0xffbef3e8:
0xaaaaaaa3 0xaaaaaaa4 0x00000000 0x00000000
0xffbef3f8:
0x00000000 0xff3dc890 0x00000001 0xffbef4ac
0xffbef408:
0xffbef4b4 0x00020c00 0x00000000 0x00000000
0xffbef418:
0xffbef448 0x000107c0 0x00000000 0xaaaaaaa1
0xffbef428:
0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8
0xffbef438:
0xff29bc20 0xffbef5fc 0x12345678 0x00000000
0xffbef448:
0x00000001
dbx> regs
current frame: [1]
g0-g3 0x00000000 0x0000000a 0x00000000 0x00000000
g4-g7 0x00000000 0x00000000 0x00000000 0x00000000
o0-o3 0x2f2f2f2f 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4
o4-o7 0x00000000 0x00000000 0xffbef378 0x0001094c
l0-l3 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3 0xbbbbbbb4
l4-l7 0x00000000 0x00000000 0x00000000 0x00000000
i0-i3 0xaaaaaaa1 0xaaaaaaa2 0xaaaaaaa3 0xaaaaaaa4
i4-i7 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a2c
y 0x00000000
ccr 0x00000099
pc 0x00010954:function1+0x64 sethi %hi(0x1f1f1c00), %l0
npc 0x00010958:function1+0x68 or %l0, 0x31f, %l0
dbx> next
stopped in function1 at line 22 in file "frameshow.c"
22 }
dbx> next
stopped in main at line 34 in file "frameshow.c"
34 final(0xDDDDDDD1, 0xDDDDDDD2);
dbx> step
stopped in final at line 25 in file "frameshow.c"
25 int i_final = 0x0FF00FF0;
dbx> next
stopped in final at line 26 in file "frameshow.c"
26 return i_final;
dbx> P $sp
$sp = 0xffbef378
dbx> P $fp
$fp = 0xffbef3e0
dbx> ex 0xffbef2a8, 0xffbef448
0xffbef2a8: 0x3f3f3f3f 0x00000000 0x00000000 0x00000000
0xffbef2b8: 0x00000000 0x00000000 0x00000000 0x00000000
0xffbef2c8: 0x3f3f3f3f 0xccccccc2 0xccccccc3 0xccccccc4
0xffbef2d8: 0x00000000 0x00000000 0xffbef310 0x000108ac
0xffbef2e8: 0x00000000 0x00000000 0x00000000 0x00000000
0xffbef2f8: 0x00000000 0x00000000 0x00000000 0x00000000
0xffbef308: 0x30303030 0x3f3f3f3f 0x2f2f2f2f 0xccccccc2
0xffbef318: 0xccccccc3 0xccccccc4 0x00000000 0x00000000
0xffbef328: 0x00000000 0x00000000 0x2f2f2f2f 0xbbbbbbb2
0xffbef338: 0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000
0xffbef348: 0xffbef378 0x0001094c 0xffbef5fc 0xccccccc1
0xffbef358: 0xccccccc2 0xccccccc3 0xccccccc4 0x00000000
0xffbef368: 0x00000000 0x00000000 0x20202020 0x2f2f2f2f
0xffbef378:
0x0ff00ff0 0x00000000 0x00000000 0x00000000
0xffbef388:
0x00000000 0x00000000 0x00000000 0x00000000
0xffbef398:
0xddddddd1 0xddddddd2 0xaaaaaaa3 0xaaaaaaa4
0xffbef3a8:
0x000222e8 0xff29bc20 0xffbef3e0 0x00010a48
0xffbef3b8:
0xffbef3e0 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3
0xffbef3c8:
0xbbbbbbb4 0x00000000 0x00000000 0xff29bc20
0xffbef3d8:
0x0ff00ff0 0x1f1f1f1f 0xddddddd1 0xddddddd2
0xffbef3e8:
0xaaaaaaa3 0xaaaaaaa4 0x00000000 0x00000000
0xffbef3f8:
0x00000000 0xff3dc890 0x00000001 0xffbef4ac
0xffbef408:
0xffbef4b4 0x00020c00 0x00000000 0x00000000
0xffbef418:
0xffbef448 0x000107c0 0x00000000 0xddddddd1
0xffbef428:
0xddddddd2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8
0xffbef438:
0xff29bc20 0x00000000 0x12345678 0x00010764
0xffbef448:
0x00000001
dbx> regs
current frame: [1]
g0-g3 0x00000000 0x0000000a 0x00000000 0x00000000
g4-g7 0x00000000 0x00000000 0x00000000 0x00000000
o0-o3 0x00000000 0x00000000 0x00000000 0x00000000
o4-o7 0x00000000 0x00000000 0xffbef378 0x00000000
l0-l3 0x0ff00ff0 0x00000000 0x00000000 0x00000000
l4-l7 0x00000000 0x00000000 0x00000000 0x00000000
i0-i3 0xddddddd1 0xddddddd2 0xaaaaaaa3 0xaaaaaaa4
i4-i7 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a48
y 0x00000000
ccr 0x00000099
pc 0x000109a8:final+0x18 ld [%fp - 0x8], %l0
npc 0x000109ac:final+0x1c ba final+0x2c
dbx> next
stopped in final at line 27 in file "frameshow.c"
27 }
dbx> next
stopped in main at line 35 in file "frameshow.c"
35 return 0;
dbx> P $sp
$sp = 0xffbef3e0
dbx> P $fp
$fp = 0xffbef448
dbx> ex 0xffbef2a8, 0xffbef448
0xffbef2a8: 0x3f3f3f3f 0x00000000 0x00000000 0x00000000
0xffbef2b8: 0x00000000 0x00000000 0x00000000 0x00000000
0xffbef2c8: 0x3f3f3f3f 0xccccccc2 0xccccccc3 0xccccccc4
0xffbef2d8: 0x00000000 0x00000000 0xffbef310 0x000108ac
0xffbef2e8: 0x00000000 0x00000000 0x00000000 0x00000000
0xffbef2f8: 0x00000000 0x00000000 0x00000000 0x00000000
0xffbef308: 0x30303030 0x3f3f3f3f 0x2f2f2f2f 0xccccccc2
0xffbef318: 0xccccccc3 0xccccccc4 0x00000000 0x00000000
0xffbef328: 0x00000000 0x00000000 0x2f2f2f2f 0xbbbbbbb2
0xffbef338: 0xbbbbbbb3 0xbbbbbbb4 0x00000000 0x00000000
0xffbef348: 0xffbef378 0x0001094c 0xffbef5fc 0xccccccc1
0xffbef358: 0xccccccc2 0xccccccc3 0xccccccc4 0x00000000
0xffbef368: 0x00000000 0x00000000 0x20202020 0x2f2f2f2f
0xffbef378: 0x0ff00ff0 0x00000000 0x00000000 0x00000000
0xffbef388: 0x00000000 0x00000000 0x00000000 0x00000000
0xffbef398: 0x0ff00ff0 0xddddddd2 0xaaaaaaa3 0xaaaaaaa4
0xffbef3a8: 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a48
0xffbef3b8: 0xffbef3e0 0xbbbbbbb1 0xbbbbbbb2 0xbbbbbbb3
0xffbef3c8: 0xbbbbbbb4 0x00000000 0x00000000 0xff29bc20
0xffbef3d8: 0x0ff00ff0 0x0ff00ff0
0xddddddd1 0xddddddd2
0xffbef3e8:
0xaaaaaaa3 0xaaaaaaa4 0x00000000 0x00000000
0xffbef3f8:
0x00000000 0xff3dc890 0x00000001 0xffbef4ac
0xffbef408:
0xffbef4b4 0x00020c00 0x00000000 0x00000000
0xffbef418:
0xffbef448 0x000107c0 0x00000000 0xddddddd1
0xffbef428:
0xddddddd2 0xaaaaaaa3 0xaaaaaaa4 0x000222e8
0xffbef438:
0xff29bc20 0x00000000 0x12345678 0x00010764
0xffbef448:
0x00000001
dbx> regs
current frame: [1]
g0-g3 0x00000000 0x0000000a 0x00000000 0x00000000
g4-g7 0x00000000 0x00000000 0x00000000 0x00000000
o0-o3 0x0ff00ff0 0xddddddd2 0xaaaaaaa3 0xaaaaaaa4
o4-o7 0x000222e8 0xff29bc20 0xffbef3e0 0x00010a48
l0-l3 0xddddddd1 0xddddddd2 0xaaaaaaa3 0xaaaaaaa4
l4-l7 0x00000000 0x00000000 0x00000000 0xff3dc890
i0-i3 0x00000001 0xffbef4ac 0xffbef4b4 0x00020c00
i4-i7 0x00000000 0x00000000 0xffbef448 0x000107c0
y 0x00000000
ccr 0x00000099
pc 0x00010a50:main+0x70 ba main+0x80
npc 0x00010a54:main+0x74 st %g0, [%fp - 0x4]
La mémoire C
Un programme C gère la mémoire de trois façons différentes:
- La mémoire globale du segment data, accessible depuis n'importe quel endroit du programme, où sont stockées les données statiques globales,
- La mémoire globale du tas, accessible depuis n'importe quel endroit du programme, où sont stockées les données dynamiquement allouées (malloc, réalloc, free, ...)
- La mémoire locale aussi appelée la pile, accessible localement seulement, où sont passés les paramètres des fonctions et stockées les données locales et temporaires.
Exemple :
#include
#include
static int i_stat = 4;
/* Stocké dans le segment data */
int i_glob;
/* Stocké dans le segment bss */
int *pi_pg;
/* Stocké dans le segment bss */
/* main est stocké dans le segment text de la zone de programme */
int main(int nargs, char **args) {
/* paramètres nargs et args stockés dans la frame numéro 1 de la pile */
int *pi_loc;
/* dans la frame 1 de la pile */
void *sbrk0;
/* nécessaire pour stocker l'adresse de base
avant le premier malloc */
sbrk0 = (void *) sbrk(0);
if (!(pi_loc = (int *) malloc(sizeof(int) * 16)))
/* réservation de 16 x sizeof(int) sur le tas */
return 1;
if (!(pi_pg = (int *) malloc(sizeof(int) * 8))) {
/* réservation de 8 x sizeof(int) sur le tas */
free(pi_loc);
return 2;
}
printf("adresse de i_stat = 0x%08x (zone programme, segment data)
", &i_stat);
printf("adresse de i_glob = 0x%08x (zone programme, segment bss)
", &i_glob);
printf("adresse de pi_pg = 0x%08x (zone programme, segment bss)
", &pi_pg);
printf("adresse de main = 0x%08x (zone programme, segment text)
", main);
printf("adresse de nargs = 0x%08x (pile frame 1)
", &nargs);
printf("adresse de args = 0x%08x (pile frame 1)
", &args);
printf("adresse de pi_loc = 0x%08x (pile frame 1)
", &pi_loc);
printf("sbrk(0) (heap) = 0x%08x (tas)
", sbrk0);
printf("pi_loc = 0x%08x (tas)
", pi_loc);
printf("pi_pg = 0x%08x (tas)
", pi_pg);
free(pi_pg);
free(pi_loc);
return 0;
}
Donne sous Sparc/Solaris :
adresse de i_stat = 0x00020c70 (zone programme, segment data)
adresse de i_glob = 0x00020ca4 (zone programme, segment bss)
adresse de pi_pg = 0x00020ca8 (zone programme, segment bss)
adresse de main = 0x0001068c (zone programme, segment text)
adresse de nargs = 0xffbeefa4 (pile frame 1)
adresse de args = 0xffbeefa8 (pile frame 1)
adresse de pi_loc = 0xffbeef4c (pile frame 1)
sbrk(0) (heap) = 0x00020c00 (tas)
pi_loc = 0x00020cb8 (tas)
pi_pg = 0x00020d08 (tas)
Parallèlement, l'utilitaire elfdump donne :
index value size type bind oth ver shndx name
[17] 0x00020c68 0x00000000 SECT LOCL D 0 .data
[21] 0x00020c88 0x00000000 SECT LOCL D 0 .bss
[47] 0x00020c70 0x00000004 OBJT LOCL D 0 .data i_stat
[60] 0x00020ca4 0x00000004 OBJT GLOB D 0 .bss i_glob
[68] 0x0001068c 0x000001e0 FUNC GLOB D 0 .text main
[80] 0x00020ca8 0x00000004 OBJT GLOB D 0 .bss pi_pg
On notera que la variables pi_pg est stockée dans le segment bss mais que les données
pointées par la variable sont elles stockées dans le tas.
De même, la variable pi_loc est stockée sur la pile, mais les données vers lesquelles elle
pointe sont stockées sur le tas.
A retenir :
- La mémoire d'un processus est assimilable à un espace contigu,
- Cet espace est organisé en différents groupes fonctionnels,
- Les données d'un programme ne sont pas toutes stockées au même endroit en fonction de leur
portée et de leur mode de réservation.
(
Table des matières)
Le tas
Exploration du tas
principes d'un allocateur memoire
Un allocateur mémoire est un ensemble de routine responsable de la gestion du tas.
Bien qu'un processus pense avoir toute la mémoire pour lui, il faut néanmoins s'assurer d'une part que cette mémoire est réellement disponible (et ne s'envolera pas toute seule lors de modifications des pages mémoires par la mmu), et d'autre part que les variables d'une fonction ne soit pas écrasées par une celles d'une autre.
Par ailleurs, les différentes sous parties d'un programme ne nécessitent pas de conserver toute la mémoire allouée pendant toute la durée de l'exécution. Par exemple, lorsque l'on referme un fichier, il est préférable libérer toute la mémoire qui lui correspond. Cet espace se verra de nouveau disponible pour ouvrir un autre document.
En résumé, l'allocateur doit se charger des taches suivantes:
- réservation de pages mémoire auprès du noyau (brk/sbrk)
- segmentation et réservation de ces pages en fonction des besoins
- remise à disposition de la mémoire précédement allouée
La réservation de pages mémoire est normalement transparent vis à vis de l'utilisateur. Par contre, la réservation et la libération de la mémoire sont des opérations en interface avec le programmeur. Les points d'entrée de ces deux opérations sont les fonctions
malloc() et
free(). A ces 2 opérations viennent s'ajouter
realloc(), qui permet de modifier la taille d'uen zone allouée.
Allocateur minimaliste
Voyons tout d'abord un allocateur minimaliste qui ne libère pas réellement la mémoire, mais dont nous pourrons nous servir le cas échéant pour débugger la mémoire.
Allocateur standards
L'allocateur minimaliste ne répond pas au problème de la libération. Il a de plus l'inconvéniant d'appeler des routines systèmes (
sbrk) peu performantes à chaque malloc.
La pile
Notion de type
Un des points les plus importants lorsque l'on
parle de langage évolué est la notion de typage. Nous
ne parlerons pas de la notion théorique de typage, mais de la
notion pratique.
Dans la pratique, un ordinateur ne reconnait aucun
type de donnée quant à son stockage en mémoire.
Il n'existe pas une mémoire spécifique pour les entiers
et une autre pour les caractères. La seule exception à
cette règle se trouve dans les registres des microprocesseurs
qui, eux, pour des raisons de performances, différencient les
nombres entiers des nombres réels.
La notion de type « de bas niveau »
correspond à la taille mémoire sur laquelle est encodée
une entité. Le type définit donc la taille de la donnée
à manipuler.
(
Table des matières)
Types simples
Les types simples sont les types prédéfinis
par le langage C: char, short, int, long, float, double, et les
pointeurs (void *). Il est à noter que quel que soit le «type»
de pointeur (char *, int * double *, void *), la taille d'encodage
est toujours la même. Aussi, un pointeur générique
peut être appelé void *.
Ces types ont des tailles fixées pour une
architecture donnée, mais varient d'une architecture à
l'autre. Il semble même que la taille d'un « octet »
n'ai pas toujours été de 8bits
2
Il est impératif
de ne pas supposer de leur taille si l'on recherche la portabilité.
On pourra utiliser
sizeof(type)
en lieu et place de la taille supposée.
1 #include
2 int main(void) {
3 printf("sizeof(char) = %d
", sizeof(char));
4 printf("sizeof(short) = %d
", sizeof(short));
5 printf("sizeof(int) = %d
", sizeof(int));
6 printf("sizeof(long) = %d
", sizeof(long));
7 printf("sizeof(long long) = %d
", sizeof(long long));
3
8 printf("sizeof(float) = %d
", sizeof(float));
9 printf("sizeof(double) = %d
", sizeof(double));
10 printf("sizeof(void *) = %d
", sizeof(void *));
11 printf("sizeof(char *) = %d
", sizeof(char *));
12 printf("sizeof(int *) = %d
", sizeof(int *));
13 printf("sizeof(double *) = %d
", sizeof(double *));
14 return 0;
15 }
donne sur linux iX86:
sizeof(char) = 1
sizeof(short) = 2
sizeof(int) = 4
sizeof(long) = 4
sizeof(long long) = 8
4
sizeof(float) = 4
sizeof(double) = 8
sizeof(void *) = 4
sizeof(char *) = 4
sizeof(int *) = 4
sizeof(double *) = 4
A retenir:
- D'un point de vue pratique, le type des données en mémoire
est assimilable à la taille des données
- Il ne faut jamais préjuger de la taille d'un type, mais
utiliser sizeof()
- Tous les pointeurs ont la même taille sur une architecture
donnée. Cette taille est cohérente avec la taille du
bus mémoire.
(
Table des matières)
Alignement
Comme nous l'avons vu dans la description de la
mémoire virtuelle, la mémoire est comparable à
un tableau.
On ne peut,
en théorie,
accéder directement qu'a une case entière dont la
taille correspond à la taille de la mémoire (32bits).
Il n'est donc pas possible d'accéder directement à une
fraction d'une case mémoire.
Or comme nous venons de le voir, les types de
donnés n'ont pas obligatoirement des tailles identiques à
la taille de la mémoire.
Prennons par exemple le caractère char.
Celui-ci est codé sur un seul octet. Mais, dans le cas d'une
mémoire de 32bits, la taille d'une case est de 4 octets. On
devra donc laisser, théoriquement, 3 octets vides.
Dans la pratique, les choses sont un
peu plus complexes car même si la taille du bus mémoire
est prépondérante, tous les octets sont directement
numérotés. Il est donc possible, par l'entremise
d'outils inclus dans les microprocesseurs et les compilateurs,
d'accéder à des données de 1, 2 ou 4 octets
directement.
Certaines architectures imposent cependant certaines contraintes d'alignement:
les données ne peuvent être stockées qu'à
des adresses multiples de la taille sur laquelle est codée ces
données et au maximum, à des adresses multiples de la
taille du bus.
Pour vérifier
si l'architecture possède une contrainte d'alignement, il
suffit de compiler et de lancer le programme suivant:
1 int main(void) {
2 struct s { char a, b, c, d, e, f, g, h, i, j;} t;
3 int *pi;
4 pi = (int *) &(t.a);
5 printf("pi = %p, i = %d
", pi, *pi);
6 pi = (int *) &(t.b);
7 printf("pi = %p, i = %d
", pi, *pi);
8 pi = (int *) &(t.c);
9 printf("pi = %p, i = %d
", pi, *pi);
10 pi = (int *) &(t.d);
11 printf("pi = %p, i = %d
", pi, *pi);
12 pi = (int *) &(t.e);
13 printf("pi = %p, f = %d
", pi, *pi);
14 pi = (int *) &(t.f);
15 printf("pi = %p, i = %d
", pi, *pi);
16 pi = (int *) &(t.g);
17 printf("pi = %p, i = %d
", pi, *pi);
18 return 0;
19 }
Si le programme se termine normalement, alors
l'architecture n'impose pas de contrainte. Dans le cas contraire, le
programme s'arrêtera brutalement avec un signal de type bus
error et génèrera un core.
Pour linux AMD Athlon, le programme tourne
normalement. Sur Solaris/UltraSparc, le programme s'arrète avec un "Bus error" ligne 5.
A retenir:
- La mémoire est adressable de plusieurs manières
différentes.
- Lorsque l'architecture impose des contraintes d'alignement,
l'adresse d'une donnée est un multiple de la taille des
données adressées si cette taille est inférieure
à la taille du bus mémoire, ou multiple de la taille
du bus .
- Nous avons vu que le typage constituait un canevas
d'interprêtation de la mémoire. Réciproquement,
n'importe quelle zone mémoire peut être interprètée
par un type ou un autre pour peu que l'alignement soit respecté.
(
Table des matières)
Types composés
Les types composés peuvent être
définis comme des agrégats de types simples ou/et
composés.
La définition de types composés se
fait à l'aide du mot réservé «struct»,
suivi de la description des différent composants.
Ces types composés définis par
« struct » fonctionnent comme les types simples
en ce qui concerne l'assignation
5:
1 #include
2 int main(void) {
3 struct s1 {int a, b;} A, B;
4 A.a = 1, A.b = 2, B.a = 3, B.b = 4;
5 A = B;
6 printf("A.a = %d
A.b = %d
", A.a, A.b);
7 return 0;
8 }
donne:
A.a = 3
A.b = 4
Par contre, il est impossible de faire des comparaisons sur ces types complexes (comme par exemple A==B).
La séquence des composants tient un rôle
important dans la définition des types composés. En
effet en raison des contraintes d'alignement précitées,
les trois structures suivantes n'utiliseront pas la même
quantité de mémoire:
1 #include
2 struct fin {
3 char a;
4 char b;
5 char c;
6 char d;
7 float x;
8 float y;
9 float z;
10 };
11 struct moyen {
12 char a;
13 char b;
14 float x;
15 char c;
16 char d;
17 float y;
18 float z;
19 };
20 struct large {
21 char a;
22 float x;
23 char b;
24 float y;
25 char c;
26 float z;
27 char d;
28 };
29 int main(void) {
30 printf("sizeof(char) = %d
", sizeof(char));
31 printf("sizeof(float) = %d
", sizeof(float));
32 printf("4 * sizeof(char) + 3 * sizeof(float) = %d
", 4 * sizeof(char) + 3 * sizeof(float));
33 printf("sizeof(fin) = %d
", sizeof(struct fin));
34 printf("sizeof(moyen) = %d
", sizeof(struct moyen));
35 printf("sizeof(large = %d
", sizeof(struct large));
36 return 0;
37 }
donne les valeurs suivantes (linux iX86/AMD):
sizeof(char) = 1
sizeof(float) = 4
4 * sizeof(char) + 3 * sizeof(float) = 16
sizeof(fin) = 16
sizeof(moyen) = 20
sizeof(large) = 28
Dans le cas de la
structure « fin », la séquence optimise
la trace mémoire de la structure. Les 4 caractères sont
contigus dans 1 case memoire de 32 bits, suivis de 3 float dont la
taille est ici de 4 octets chacuns.
Dans le cas de la structure « large », la trace
mémoire est maximale: pour chaque caractère, 4 octets
sont occupés pour 1 seul de réellement utilisé.
Dans le cas de la
structure « moyen », la trace mémoire
n'est pas complètement optimisée et les 2 couple de
« char » sont codés sur chacun 4 octets.
A retenir:
- L'ordre des données définies dans
une structure influe sur la taille de la mémoire utilisée
afin de respecter les contraintes d'alignement (même si
l'architecture n'en possède a priori pas).
- De même que les types simples, les types complexes
constituent un canevas d'interprêtation de la mémoire.
Réciproquement, toute zone de mémoire respectant les
contraintes d'alignement peut être interprêtée
par une structure.
(
Table des matières)
Tableaux
Les tableaux sont des
zones de mémoires réservées et censées
rec