Changes between Version 27 and Version 28 of Archi-1-TD10
- Timestamp:
- Nov 15, 2023, 5:22:26 PM (13 months ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Archi-1-TD10
v27 v28 172 172 173 173 174 Le noyau et l'application sont deux exécutables compilés indépendamment mais pas qui ne sont pas indépendants. Vous savez déjà que l'application appelle les services du noyau avec l'instruction `syscall`, voyons comment cela se passe vraiment depuis le code C. Certaines questions sont proches de celles déjà posées, c'est volontaire.174 Le noyau et l'application sont deux exécutables compilés indépendamment mais qui ne sont pas indépendants puisqu'on doit passer du noyau à l'application et inversement. Vous savez déjà que l'application appelle les services du noyau avec l'instruction `syscall`, voyons comment cela se passe vraiment depuis le code C. Certaines questions sont proches de celles déjà posées, c'est volontaire. 175 175 176 176 … … 178 178 179 179 180 1. Comment imposer le placement d'adresse d'une fonction ou d'une variable en mémoire ? (C9 S18+S22+S23 C10 annexe S6+S8)181 {{{#!protected ------------------------------------------------------------------------------------ 182 '' 183 - C'est l'éditeur de lien qui est en charge du placement en mémoire du code et des données, et c'est dans le fichier ldscript `kernel.ld` ou `user.ld` que le programmeur peut imposer ses choix.184 - Pour placer une fonction à une place, la méthode que vous avez vu consiste185 - à créer une section grâce à la directive `.section` en assembleur ou à la directive `__attribute__((section()))` enC186 - puis à positionner la section créée dans la description des `SECTIONS` du ldscript.180 1. Comment imposer le placement d'adresse d'une fonction ou d'une variable en mémoire lorsqu'on produit un programme binaire exécutable, c'est-à-dire avec quel outil de la chaîne de compilation et avec quel fichier de configuration de cet outil ? (C9 S18+S22+S23 C10 annexe S6+S8) 181 {{{#!protected ------------------------------------------------------------------------------------ 182 '' 183 - C'est l'éditeur de lien qui est en charge du placement en mémoire du code et des données, et c'est dans les fichiers ldscript `kernel.ld` ou `user.ld` que le programmeur peut imposer ses choix de placement dans l'espace d'adressage. 184 - Pour placer une fonction à une adresse précise, la méthode que vous avez vu consiste 185 - à créer une section grâce à la directive `.section` en assembleur ou grâce à la directive `__attribute__((section()))` pour les programmes C 186 - puis à positionner la section ainsi créée dans la description des `SECTIONS` du fichier ldscript concerné. 187 187 '' 188 188 }}} 189 1. Regardons comment la fonction `kinit()` appelle la fonction `_start()`, il y a deux fichiers impliqués `kinit.c` et `hcpua.S` , les commentaires ont été retirés. Pour rappel, la fonction `_start()` est la fonction d'entrée de l'application utilisateur, c'est elle qui appelle la fonction `main()`. La fonction `_start()` est donc dans le code de l'application, et non pas dans le noyau. Cependant le noyau doit connaitre son adresse afin de pouvoir y sauter et ainsi entrer dans l'application.189 1. Regardons comment la fonction `kinit()` appelle la fonction `_start()`, il y a deux fichiers impliqués `kinit.c` et `hcpua.S`. Pour rappel, la fonction `_start()` est la fonction d'entrée de l'application utilisateur, c'est elle qui appelle la fonction `main()`. La fonction `_start()` est donc dans le code de l'application, et non pas dans le noyau. Cependant le noyau doit connaitre son adresse afin de pouvoir y sauter et ainsi entrer dans l'application. 190 190 {{{#!c 191 191 kinit.c: … … 193 193 { 194 194 [...] 195 extern int _start; 196 app_load (&_start); 195 extern int _start; # declaree ailleurs a une adresse connue de l'editeur de lien 196 app_load (&_start); # appel de la fonction app_load definie dans hcpua.S 197 197 } 198 198 … … 200 200 .globl app_load 201 201 app_load: 202 mtc0 $4, $14 203 li $26, 0x12 204 mtc0 $26, $12 205 la $29, __data_end 202 mtc0 $4, $14 # $4 contient l'argument 203 li $26, 0x12 # $26 <-- 0x12 == 0b0001010 204 mtc0 $26, $12 # c0_sr <-- 0x12 205 la $29, __data_end # initialisation du pointeur de pile 206 206 eret 207 207 }}} … … 218 218 '' 219 219 }}} 220 Quels sont les registres utilisés dans le code de `app_load `? Que savez-vous de l'usage de `$26 `? Quels sont les registres modifiés ?Expliquez pour chacun la valeur affectée. \\221 {{{#!protected ------------------------------------------------------------------------------------ 222 '' 223 - Les registres utilisés par `app_load` sont `$4`, `$26`, `$29` du banc GPR et `$12` (`c0_sr`) et `$14` (`c0_epc`) du banc de registres système.220 Quels sont les registres utilisés dans le code de `app_load `?\\Que savez-vous de l'usage de `$26 `?\\Quels sont les registres modifiés ?\\Expliquez pour chacun la valeur affectée. \\ 221 {{{#!protected ------------------------------------------------------------------------------------ 222 '' 223 - Les registres utilisés par `app_load` sont `$4`, `$26`, `$29` du banc GPR et `$12` (`c0_sr`) et `$14` (`c0_epc`) du banc de registres du coprocesseur `0`. 224 224 - `$26` est un registre GPR temporaire pour le noyau, il peut l'utiliser sans le sauver avant et donc sans le restaurer. 225 225 - Il y a 4 registres affectés, dans l'ordre : … … 228 228 - Le registre système `$12` nommé `c0_sr`, il reçoit la valeur `0x12`, donc les bits `UM`, `EXL` et `IE` prennent respectivement les valeurs `1`, `1` et `0` 229 229 - UM = 1 et IE = 0, signifie que l'on est normalement en mode `user` avec les interruptions masquées, 230 **mais** comme `EXL`=`1`, alors on reste en mode `kernel` avec interruptions masquées. 231 - Le registre GPR `$29` reçoit l'adresse de la première adresse **après** la section `.data`. C'est le haut de la pile. 230 **mais** comme `EXL`=`1`, alors on reste en mode `kernel` avec interruptions masquées.\\ 231 Ici les interruptions sont masquées même quand exécute l'application parce que le noyau ne contient pas encore le gestionnaire des interruptions. En effet, on construit le noyau par morceau et le gestionnaire des interruptions est vu au cours suivant. 232 - Le registre GPR `$29` reçoit l'adresse de la première adresse en haut de la région `data_region`. C'est le haut de la pile pour l'utilisateur. 232 233 '' 233 234 }}} … … 241 242 {{{#!protected ------------------------------------------------------------------------------------ 242 243 '' 243 - Comme dans la fonction `kinit()`, il faut explicitement initialiser les variables globales non initialisées dans le programme C. 244 - Comme dans la fonction `kinit()`, il faut explicitement initialiser les variables globales non initialisées dans le programme C. En effet, le programmeur suppose que les variables globales non initialisées explicitement dans le programme C sont à 0. Comme ces variables ne sont pas explicitement initialisées, elles n'occupent pas de place dans le fichier exécutable, on sait juste ou elles sont placées en mémoire. 244 245 - Si on sort de la fonction `main()`, l'application s'achève. Cela signifie qu'il faut appeler la fonction `exit()` qui effectue l'appel système SYSCALL_EXIT. Cette appel est réalisé au cas où l'application n'aurait pas explicitement exécuté `exit()`. Dans ce cas la valeur rendue par l'application est la valeur de retour de la fonction `main()`. 245 246 ''