181 | | 1. En assembleur, vous utilisez les sections prédéfinies `.data` et `.text` pour placer respectivement les data et le code ou alors vous pouvez créer vos propres sections avec la directive `.section` (nous avons utilisé cette possibilité pour la section `.boot`). Il est aussi possible d'imposer ou de créer des sections en langage C avec le mot clé `__attribute__`. Ce mot clé du C permet de demander certains comportements au compilateur. Il y a en a beaucoup (si cela vous intéresse vous pouvez regarder dans la [https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html doc de GCC sur les attributs]. En cours, nous avons vu un attribut permettant de désigner ou créer une section dans laquelle est mise la fonction concernée. Quelle était la syntaxe de cet attribut (regardez sur le slide 37). |
182 | | {{{#!protected ------------------------------------------------------------------------------------ |
183 | | ''''''''''''''' |
184 | | - `__attribute__ ((section (".crt0")))`\\Remarquez la syntaxe un peu curieuse avec les doubles underscore et les doubles parenthèses. |
| 181 | 1. En assembleur, vous utilisez les sections prédéfinies `.data` et `.text` pour placer respectivement les data et le code ou alors vous pouvez créer vos propres sections avec la directive `.section` (nous avons utilisé cette possibilité pour la section `.boot`). Il est aussi possible d'imposer ou de créer des sections en langage C avec le mot clé `__attribute__`. Ce mot clé du C permet de demander certains comportements au compilateur. Il y a en a beaucoup (si cela vous intéresse vous pouvez regarder dans la [https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html doc de GCC sur les attributs]. En cours, nous avons vu un attribut permettant de désigner ou créer une section dans laquelle est mise la fonction concernée. Quelle était la syntaxe de cet attribut (regardez sur le slide 38). |
| 182 | {{{#!protected ------------------------------------------------------------------------------------ |
| 183 | ''''''''''''''' |
| 184 | - `__attribute__ ((section (".start")))`\\Remarquez la syntaxe un peu curieuse avec les doubles underscore et les doubles parenthèses. |
263 | | 13 // put bss sections to zero. bss contains uninitialised global variables |
264 | | 14 extern int __bss_origin; // first int of bss section |
265 | | 15 extern int __bss_end; // first int of above bss section |
266 | | 16 for (int *a = &__bss_origin; a != &__bss_end; *a++ = 0); |
267 | | 17 |
268 | | 18 // this code allows to exit the kernel to go to user code |
269 | | 19 __asm__ volatile ( "la $26, __text_origin \n" // get first address of user code |
270 | | 20 "mtc0 $26, $14 \n" // put it in c0_EPC |
271 | | 21 "li $26, 0b00010010 \n" // next status [UM,0,ERL,EXL,IE] |
272 | | 22 "mtc0 $26, $12 \n" // UM <- 1, IE <- 0, EXL <- 1 |
273 | | 23 "la $29, __data_end \n" // define new user stack pointer |
274 | | 24 "eret \n"); // j EPC and EXL <- 0 |
275 | | 25 } |
276 | | }}} |
277 | | {{{#!protected ------------------------------------------------------------------------------------ |
278 | | ''''''''''''''' |
279 | | - L'adresse `__crt0` est la première adresse de la section `text` dans laquelle se trouve le code de l'application. |
280 | | - Elle vaut `0X7F400000`. |
281 | | - 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 |
282 | | dans la partie accessible en mode user. |
283 | | - A cette adresse, on place la fonction `__start()`. |
284 | | - 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. |
285 | | ''''''''''''''' |
286 | | }}} |
287 | | 1. Dans le code C de la question précédente, à quoi servent les lignes 14 à 16? Pourquoi faire des déclarations `extern`? |
288 | | {{{#!protected ------------------------------------------------------------------------------------ |
289 | | ''''''''''''''' |
290 | | - Ces lignes servent à mettre à 0 la zone des variables globales non initialisées explicitement par le programme. |
291 | | - Les déclarations `extern` permettent d'informer le compilateur que les adresses `__bss_orgin` et `__bss_end` |
292 | | existent ailleurs. De fait, elles sont définies dans le fichier `kernel.ld`. |
| 271 | 13 void exit (int status) |
| 272 | 14 { |
| 273 | 15 syscall( status, 0, 0, 0, SYSCALL_EXIT); // never returns |
| 274 | 16 } |
| 275 | }}} |
| 276 | |
| 277 | Le code de cette fonction est dans le fichier `tp2/4_libc/ulib/crt0.c` |
| 278 | {{{#!c |
| 279 | 1 //int syscall (int a0, int a1, int a2, int a3, int syscall_code) |
| 280 | 2 __asm__ ( |
| 281 | 3 ".globl syscall \n" |
| 282 | 4 "syscall: \n" |
| 283 | 5 " lw $2,16($29) \n" |
| 284 | 6 " syscall \n" |
| 285 | 7 " jr $31 \n" |
| 286 | 8 ); |
| 287 | }}} |
| 288 | Combien d'arguments a la fonction `syscall()`? |
| 289 | Comment la fonction `syscall()` reçoit-elle ses arguments ? |
| 290 | A quoi sert la ligne 3 de la fonction `syscall()` et que se passe-t-il si on la retire ? |
| 291 | Expliquer la ligne 5 de la fonction `syscall()`. |
| 292 | Aurait-il été possible de mettre le code de la fonction `syscall()` dans un fichier `.S` ? |
| 293 | {{{#!protected ------------------------------------------------------------------------------------ |
| 294 | ''''''''''''''' |
| 295 | - La fonction `syscall()` a 5 a arguments |
| 296 | - Elle reçoit ses 4 premiers arguments dans les registres $4 à $7 et le 5e dans la pile. |
| 297 | - 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 le linker. |
| 298 | - Le noyau attend le numéro de service dans `$2`. Or le numéro du service est le 5e arguments de la fonction `syscall()`. La ligne 5 permet d'aller le chercher dans la pile. |