# TP1 : Mémoire > Dans le répertoire [scripts](./src/scripts), vous avez 2 scripts qui permettent de formater sur la sortie standard les > interfaces `/proc/pid/maps` et `/proc/pid/smaps` d'un processus quelconque. #### Ex1 Compilez avec `g++` le programme [alignement.c](./src/alignement.c), et exécutez. Vérifiez qie la taille et l'alignement de chaque structure est bien conforme aux règles vues en cours. #### Ex2 Soit le [programme](./src/adresses_virtuelles.c) suivant qui affiche les adresses virtuelles de certaines variables lors de l'exécution du processus correspondant : ```c /* adresses virtuelles d'un processus */ #include #include #include #include int t[1000] = {[0 ... 999] = 2}; int main(int argc, char * argv[]) { int i=3; static int j = 3; char * m = (char*)malloc(1); printf("je suis le pid %d\n\n",getpid()); /* ------- Affichage des adresses --------*/ printf("main\t=\t%p\n",main); printf("&argc\t=\t%p\n",&argc); printf("&i\t=\t%p\n",&i); printf("&j\t=\t%p\n",&j); printf("t\t=\t%p\n",t); printf("m\t=\t%p\n",m); getchar(); } ``` En utilisant le (pseudo) fichier `/proc/pid/maps`, vérifiez à quel segment de pages ces adresses appartiennent. Vous pouvez utiliser le script python [vmap.py](./src/scripts/vmap.py). #### Ex3 L'interface (pseudo-fichier) `proc/pid/smaps` montre la consommation mémoire d'un processus. On peut le formater avec la commande `pmap -X` ou avec le script python [parse_smaps.py](./src/scripts/parse_smaps.py). Le but de l'exercice est de voir ce qui se passe au niveau de la mémoire d'un processus suivant les différents mode d'allocation. Le programme `null.c` permet d'avoir un point de comparaison. Vérifiez la consommation mémoire dans les cas suivants : 1. Allocation statique [buf.c](./src/ex3/buf.c). 2. Allocation sur la pile [stack.c](./src/ex3/stack.c), 3. Allocation sur le tas [heap.c](./src/ex3/heap.c), 4. Allocation (grande quantité) sur le tas [huge.c](./src/ex3/huge.c). 5. Allocation par mapping [mmap.c](./src/ex3/mmap.c). #### Ex4 Soit le [programme](./src/bss_data.c) suivant : ```c /* segment bss et data */ #define N 10000 int t[N]; /* version 1 */ //int t[N]={1}; /* version 2 */ int main() { return 0; } ``` 1. Compilez le programme. Avec la commande `size`, regardez les différents segments du programme. Où se trouve le tableau `t` ? Augmentez la valeur de N. La taille de l'exécutable a-t-elle changé ? pourquoi ? 2. Recommencez avec la version 2. Expliquez. #### Ex5 Soit le [programme](./src/ij_ji.c) suivant : ```c /* accès mémoire */ #include #include #include #define N 8192 int t[N][N]; static inline double tstamp(void) { struct timespec tv; clock_gettime(CLOCK_REALTIME, &tv); return tv.tv_sec + tv.tv_nsec * 1.0e-9; } int main() { int i,j; double t1,t2; t1=tstamp(); /* version 1 */ for(i=0;i+---------------------------+ |###########################| \ |###########################| | |###########################| | already allocated |###########################| | |###########################| | |###########################| / pos +-------------->----------------------------+ | | \ | | | | | | | | | | | | | | | free space | | | | | | | | | | | | | | | | | / +---------------------------+ ``` C'est la fonction ```c void * my_alloc(size_t sz) ``` qui s'occupe de renvoyer l'adresse d'un bloc libre. On ne se préoccupe pas de désallocation, ni d'alignement. Une allocation consiste simplement à incrémenter (si c'est possible) la valeur de `pos`, et à retourner l'adresse du bloc alloué. Implanter cette fonction, et tester. #### Ex8 Ecrire une fonction ```c void hexdump(void * ptr,size_t size); ``` qui affiche sur la sortie standard le contenu de la mémoire `[ptr,ptr+size[` au format : ``` XXXXXXXX BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB |CCCCCCCCCCCCCCCC| ``` (comme la commande shell) - `XXXXXXXXX` représente l'adresse du premier octet de la ligne - `BB` la valeur hexadécimale de chaque octet - `|CCCCCCCCCCCCCCCC|` la correspondance ascii de chaque octet (`.` si non affichable) Testez avec les objets suivants et expliquez : ```c /* alignement et objets */ struct exemple1 { int x; int y; int z; int w; }; struct exemple2 { char x; char y; char z; char w; }; struct exemple3 { int x; int y; char z; char w; }; struct exemple4 { int x; char y; int z; char w; }; union exemple5 { int x; char y; int z; char w; }; int main() { int a[4] = {1,2,3,4}; char c[4] = {'a','b','c','d'}; struct exemple1 ex1 = {1,2,3,4}; struct exemple2 ex2 = {'a','b','c','d'}; struct exemple3 ex3 = {1,2,'c','d'}; struct exemple4 ex4 = {1,'c',2,'d'}; union exemple5 ex5; int x = 61; char y = 62; int z = 63; char w = 64; ex5.x=62;ex5.y=63;ex5.z=64;ex5.w=65; // appelez hexdump pour chaque variable return 0; } ``` Est-ce conforme à ce que l'on a vu en cours concernant l'alignement en mémoire ?