Changes between Version 27 and Version 28 of Archi-1-TD10


Ignore:
Timestamp:
Nov 15, 2023, 5:22:26 PM (13 months ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Archi-1-TD10

    v27 v28  
    172172
    173173
    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.
     174Le 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.
    175175
    176176
     
    178178
    179179
    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 consiste
    185   - à créer une section grâce à la directive `.section` en assembleur ou à la directive `__attribute__((section()))` en C
    186   - puis à positionner la section créée dans la description des `SECTIONS` du ldscript.
     1801. 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é.
    187187''
    188188}}}
    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.
     1891. 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.
    190190{{{#!c
    191191kinit.c:
     
    193193    {
    194194        [...]
    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
    197197    }
    198198
     
    200200    .globl app_load
    201201    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
    206206        eret 
    207207}}}
     
    218218''
    219219}}}
    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`.
    224224- `$26` est un registre GPR temporaire pour le noyau, il peut l'utiliser sans le sauver avant et donc sans le restaurer.
    225225- Il y a 4 registres affectés, dans l'ordre :
     
    228228  - 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`
    229229    - 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.
    232233''
    233234}}}
     
    241242{{{#!protected ------------------------------------------------------------------------------------
    242243''
    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.
    244245- 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()`.
    245246''