Changes between Version 12 and Version 13 of AS6-TME-B1


Ignore:
Timestamp:
Feb 9, 2022, 9:29:40 AM (3 years ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AS6-TME-B1

    v12 v13  
    659659'''''''''''''''
    660660}}}
    661 1. Vous avez appris à écrire des programmes assembleur, mais parfois il est plus simple, voire nécessaire, de mélanger le code C et le code assembleur. Dans l'exemple ci-dessous, nous voyons comment la fonction `kinit()` procède pour entrer dans la fonction placée à l'adresse `__crt0` définie dans le fichier `kernel.ld`.\\Remarquez la syntaxe, ici `volatile` permet de dire au compilateur d'insérer le code tel que sans le modifier. Notez aussi l'absence de `,` entre les chaînes de caractères. Le premier argument de `__asm__` est une chaîne de caractères **unique** dans laquelle les instructions sont séparées par de `\n`. Il peut y avoir d'autres arguments, nous n'en aurons pas besoin.\\ \\Dans quelle section se trouve l'adresse `__crt0`? Combien vaut-elle? Est-ce que cette valeur est imposée par le processeur MIPS comme l'adresse de boot ou d'entrée dans le kernel? Quelle fonction est à cette adresse? Pourquoi doit-on écrire ce code en assembleur?
    662 {{{#!c
    663   9 void kinit (void)
    664  10 {
    665  11     kprintf (0, banner);
     6611. Vous avez appris à écrire des programmes assembleur, mais parfois il est plus simple, voire nécessaire, de mélanger le code C et le code assembleur. Dans l'exemple ci-dessous, nous voyons comment la fonction `syscall()` est écrite. Cette fonction utilise l'instruction `syscall`.\\Deux exemples d'usage de la fonction `syscall()` pris dans le fichier `tp2/4_libc/ulib/libc.c`
     662{{{#!c
     663  1 int fprintf (int tty, char *fmt, ...)
     664  2 {
     665  3     int res;
     666  4     char buffer[PRINTF_MAX];
     667  5     va_list ap;
     668  6     va_start (ap, fmt);
     669  7     res = vsnprintf(buffer, sizeof(buffer), fmt, ap);
     670  8     res = syscall (tty, (int)buffer, 0, 0, SYSCALL_TTY_PUTS);
     671  9     va_end(ap);
     672 10     return res;
     673 11 }
    666674 12
    667  13     // put bss sections to zero. bss contains uninitialised global variables
    668  14     extern int __bss_origin;    // first int of bss section
    669  15     extern int __bss_end;       // first int of above bss section
    670  16     for (int *a = &__bss_origin; a != &__bss_end; *a++ = 0);
    671  17
    672  18     // this code allows to exit the kernel to go to user code
    673  19     __asm__ volatile (   "la     $26,    __text_origin  \n"     // get first address of user code
    674  20                          "mtc0   $26,    $14            \n"     // put it in c0_EPC
    675  21                          "li     $26,    0b00010010     \n"     // next status [UM,0,ERL,EXL,IE]
    676  22                          "mtc0   $26,    $12            \n"     // UM <- 1, IE <- 0, EXL <- 1
    677  23                          "la     $29,    __data_end     \n"     // define new user stack pointer
    678  24                          "eret                          \n");   // j EPC and EXL <- 0
    679  25 }
    680 }}}
    681 {{{#!protected ------------------------------------------------------------------------------------
    682 '''''''''''''''
    683 - L'adresse `__crt0` est la première adresse de la section `text` dans laquelle se trouve le code de l'application.
    684 - Elle vaut `0X7F400000`.
    685 - Cette adresse n'est pas imposée par le MIPS. C'est le choix des architectes du SoC. La seule condition est que cette adresse soit
    686   dans la partie accessible en mode user.
    687 - A cette adresse, on place la fonction `__start()`.
    688 - On est obligé d'écrire ce code en assembleur parce que la manière de changer de mode (de `kernel` à `user`) est propre à chaque processeur. Il n'y a aucun moyen de le faire en C.
    689 '''''''''''''''
    690 }}}
    691 1. Dans le code C de la question précédente, à quoi servent les lignes 14 à 16? Pourquoi faire des déclarations `extern`?
    692 {{{#!protected ------------------------------------------------------------------------------------
    693 '''''''''''''''
    694 - Ces lignes servent à mettre à 0 la zone des variables globales non initialisées explicitement par le programme.
    695 - Les déclarations `extern` permettent d'informer le compilateur que les adresses `__bss_orgin` et `__bss_end`
    696   existent ailleurs. De fait, elles sont définies dans le fichier `kernel.ld`.
    697 '''''''''''''''
     675 13 void exit (int status)
     676 14 {
     677 15     syscall( status, 0, 0, 0, SYSCALL_EXIT);        // never returns
     678 16 }
     679}}}
     680 Le code de cette fonction est dans le fichier `04_libc/ulib/crt0.c`
     681{{{#!c
     682  1 //int syscall (int a0, int a1, int a2, int a3, int syscall_code)
     683  2 __asm__ (
     684  3 ".globl syscall     \n"         
     685  4 "syscall:           \n"         
     686  5 "   lw  $2,16($29)  \n"         
     687  6 "   syscall         \n"         
     688  7 "   jr  $31         \n"         
     689  8 );
     690}}}
     691 Combien d'arguments a la fonction `syscall()`?
     692 Comment la fonction `syscall()` reçoit-elle ses arguments ?
     693 A quoi sert la ligne 3 de la fonction `syscall()` et que se passe-t-il si on la retire ?
     694 Expliquer la ligne 5 de la fonction `syscall()`.
     695 Aurait-il été possible de mettre le code de la fonction `syscall()` dans un fichier `.S` ?
     696{{{#!protected ------------------------------------------------------------------------------------
     697''
     698- La fonction `syscall()` a 5 a arguments
     699- Elle reçoit ses 4 premiers arguments dans les registres $4 à $7 et le 5e (le numéro de service) dans la pile.
     700- La ligne 3 sert à dire que syscall est une étiquette utilisée dans un autre fichier. `.globl` signifie **glob**al **l**abel. Si on la retire, il y aura un problème lors de l'édition de lien. `syscall()` ne sera pas trouvé par l'éditeur de liens.
     701- Le noyau attend le numéro de service dans `$2`. Or le numéro du service est le 5e argument de la fonction `syscall()`. La ligne 5 permet d'aller le chercher dans la pile.
     702- oui, ce code de la fonction `syscall()` qui fait appel à l'instruction `syscall` aurait pu être mis dans un fichier en assembleur, mais cela aurait demandé d'avoir un fichier de plus, pour une seule fonction. Dans une version plus évoluée du système, il y aura un d'autres fonctions assembleur, alors on créera un fichier assembleur pour les réunir.
     703''
    698704}}}
    699705