Dernières
nouvelles:
Les Linux
iens peuvent rencontrer un problème de compilation des outils
donnés, notamment en ce qui concerne assembler
. Le problème
est l'abscence de définition de la fonction yywrap
. Pour le
corriger, il suffit d'éditer le source assembler.lex
et
ajouter la directive %option noyywrap
.
Il est demandé de réaliser en langage C un émulateur de machine/système contenant divers composants comme un gestionnaire de processus avec ordonnanceur préemptif, une communication interprocessus par signaux asynchrones, un moniteur de synchronisation.
La machine/système Istérix devra exécuter des binaires (code machine Istérix) obtenus par assemblage (compilation élémentaire) de programmes sources écrits dans le langage Programmatix dont on trouvera la description plus loin. Istérix est une machine dont les instructions sont de deux types: instructions ordinaires (calculs, contrôle de l'exécution, etc) et instructions système (création de processus, signaux, etc.). La «structure» système qui représente l'exécution d'un binaire s'appelle un processus.
À son démarrage, le système Istérix commence par charger un binaire Istérix donné en entrée standard du processus Unix réalisant l'émulation. Ce programme est alors chargé en mémoire, les diverses initialisations nécessaires au bon fonctionnement du système sont réalisées et l'exécution de la première instruction du programme est lancée. Le régime de croisère est alors atteint.
Dans ce régime, l'émulateur se contente d'exécuter les instructions des divers processus en cours d'exécution. Puis, lorsqu'il n'existe plus aucun processus à exécuter la machine s'arrête.
L'émulateur sera un simple processus Unix.
Un processus Istérix est une structure entièrement contenue dans la mémoire Istérix (voir plus loin). Elle contient toutes les informations nécessaires à la bonne exécution du programme associé: structure de contrôle, instructions, données et pile.
Les instructions, données et pile constituent l'espace d'adressage du processus: la zone d'instruction est de taille au plus 256 instructions (8 octets pour une instruction), la zone de données est de 256 octets, et la zone de pile d'au plus 256 octets.
La structure de contrôle du processus contient différentes informations que l'on jugera nécessaires d'y mettre et qui doivent permettre une bonne exécution du processus associé, on y trouvera par exemple: l'adresse physique de la zone d'instruction, l'adresse physique de la zone de données, l'adresse physique de la pile, le numéro de l'instruction en cours d'exécution, l'état du processus, son code de retour, masque des signaux, etc.
On notera qu'un binaire Istérix fait toujours des adressages virtuels. Ainsi, dans un processus, une instruction faisant référence au chargement d'une donnée située à l'adresse 10, ne fait pas référence à l'adresse physique 10 mais à la 10ième donnée de la zone de données du processus (idem pour les instructions de contrôle de l'exécution qui font référence à des adresses en zone d'instruction et pour la pile dans la zone de pile...).
La mémoire du système Istérix sera constituée d'un unique tableau de caractères du processus Unix réalisant la simulation (voir l'exécuteur de code donné en exemple).
Dans cette mémoire, on trouvera non seulement les programmes binaires, les zones de données et piles mais aussi la liste des structures de contrôle des différents processus.
Programmatix
Ce langage rudimentaire permet d'écrire plus simplement des programmes à
exécuter par la machine Istérix. Le programme source peut être assemblé (en
utilisant la commande assembler
fournie) pour obtenir un binaire
Istérix. Pour faciliter la tâche il est conseillé de nommer les binaires en
utlisant une seule lettre (éventuellement agrémentée d'une
«extension»), comme par exemple f.ist
ou
simplement f
(pour comprendre pourquoi, consultez le description
de l'instruction EXEC
plus loin).
La conception d'un assembleur dépassant le cadre de ce cours, cet outil
vous est fourni (avec ses sources). Nous déconseillons vivement aux
étudiants de s'attacher à en comprendre le fonctionnement dans
l'immédiat. Faites ce qui est demandé, si le coeur vous en dit,
vous pourrez toujours l'examiner par la suite.. Par contre il est
vivement conseillé de consulter le code du desassembler
qui lui
vous donnera d'excellentes indications sur la structure du code machine. Une
autre excellente idée est aussi d'observer le code du processeur (de
nom processor
) qui permet d'exécuter un binaire Istérix
(seulement les instructions ordinaires évidemment!).
Le langage est constitué de deux types d'instructions:
Dans le tableau suivant, on trouvera la liste des instructions, la liste de leurs arguments et leur correspondance (approximative) en langage C. Les arguments sont de trois types:
Mnémonique | Arguments | instruction C/Unix |
---|---|---|
ASSIGN |
réf, réf_ou_cste |
réf = réf_ou_cste; |
ASSIGN+ |
réf, réf_ou_cste |
réf += réf_ou_cste; |
ASSIGN- |
réf, réf_ou_cste |
réf -= réf_ou_cste; |
ASSIGN* |
réf, réf_ou_cste |
réf *= réf_ou_cste; |
IF |
réf_ou_cste, réf_ou_cste, étiquette |
if (réf_ou_cste==réf_ou_cste) goto étiquette; |
JUMP |
étiquette | goto étiquette; |
CALL |
étiquette | étiquette(); |
RET |
return; |
|
FORK |
réf | réf = fork(); |
EXEC |
réf_ou_cste | exec(réf_ou_cste); |
EXIT |
réf_ou_cste | exit(réf_ou_cste); |
WAIT |
réf, réf |
réf = wait(réf); |
SIGNAL |
réf_ou_sig, étiquette |
signal(réf_ou_cste,étiquette); |
KILL |
réf_ou_sig, réf |
kill(réf_ou_cste,réf); |
READ |
réf | read(STDIN_FILENO,réf,1); |
WRITE |
réf_ou_cste | write(STDOUT_FILENO,réf_ou_cste,1); |
GETPPID |
réf | réf = getppid(); |
LCK |
cste | semop() avec semop = -1; |
UNLCK |
cste | semop() avec semop = +1; |
Les arguments sont de quatre types:
*
(le
nombre est le numéro d'une case mémoire dont le contenu est le
numéro de la case mémoire à consulter);#
nombre;U_SIGILL
,
U_SIGMEM
, U_SIGUSER
ou
U_SIGKILL
;:
) et
permettre au programmeur d'utiliser des symboles pour ses sauts ou appels
de fonctions.On notera la possibilité de commenter du code Programmatix en commençant
une ligne par le caractère /
.
Un assembleur Programmatix est fourni. Il ne permet d'écrire qu'une seule instruction par ligne de texte, et une instruction n'est jamais située en début de ligne, mais est toujours précédée d'au moins un espace ou une tabulation.
IMPORTANT: un programme Programmatix doît obligatoirement contenir une
instruction étiquetée par debut
et permettant d'indiquer le
point d'entrée du programme (équivalent du main()
du C).
Ce qui suit est un exemple de programme source U:
/ On commence par compter jusqu'a 10 debut: ASSIGN 13,#0 incr: ASSIGN+ 13,#1 IF 13,#10,fin_incr JUMP incr / On essaye d'appeler une fonction fin_incr: CALL remise_a_zero / On tente de capturer SIGUSER SIGNAL U_SIGUSER,sig_handler / Et un petit fork/exec/wait FORK 1 IF 1,#0,fils / Le pere attend WAIT 2,3 / Il ecrit 'b' WRITE #65 EXIT #0 remise_a_zero: ASSIGN 13,#0 RET / Le code du fils! fils: / Il envoie un SIGUSER a son pere GETPPID 5 KILL U_SIGUSER,5 / Il exec sur 'a' EXEC #64 EXIT #1 sig_handler: WRITE #64 RET
Vous trouverez dans le ficher isterix.tar.gz l'ensemble des sources utiles pour démarrer le projet.
Nous insistons: ll est formellement déconseillé de modifier quoi que ce soit dans les programmes fournis, vous y perdriez un temps considérable pour un gain nul ou presque.
Le seul fichier à modifier (éventuellement) est le Makefile
pour paramétrer la compilation sur votre système. Les seuls programmes
intéressants à étudier sont: desassembler.c
et processor.c
.
L'assembleur a pour syntaxe d'appel: assembler source.u
objet
.
Le désassembleur a pour syntaxe d'appel: desassembler < objet
.
Le processeur a pour syntaxe d'appel: processor
< objet
. Note: le processeur n'est qu'une base de travail...
Il est demandé d'écrire un programme en langage C permettant de simuler des exécutions de programmes binaires Istérix. Dans le système Istérix, il s'agira de processus qui seront ordonnancés en partageant le temps par préemption (sur une base atomique simple comme par exemple quatre instructions/processus).
Le système Istérix devra utiliser un adressage virtuel pour les processus. Adressage qui pourra permettre de partager le code lorsque différents processus exécuteront le même code.
L'instruction EXEC
qui permet de recouvrir le code du
processus courant par un nouveau code obtient le nouveau code à charger en
effectuant des lectures sur le fichier (du système Unix) dont le nom est
donnée par le paramètre. Ce dernier est toujours un entier (obtenu
éventuellement par référence) utilisé comme code ascii pour obtenir
le nom du fichier à charger. Ainsi une instruction
comme EXEC #65
permettra de charger le programme contenu dans le
fichier A
(avec une extension prédéfinie si nécessaire).
L'instruction WAIT
prend deux arguments, le premier sera
l'adresse où sera rangée l'identité du fils terminé et la seconde celle
contenant le code de retour.
Les instructions READ
ou WRITE
ne permettent de
lire ou d'écrire qu'un seul caractère à la fois et dont le code ASCII est
donné en argument (écrire) ou renvoyé par le système (lire). Si l'écriture
est immédiate (par exemple affichage d'un message: le processus numéro
87 a écrit le caractère ASCII 64 'A'
), la lecture provoque le blocage
du processus en cours tant qu'aucune donnée ne lui a été fournie par
l'interface (on peut envisager un tampon de lecture).
Le quantum de temps alloué à un processus est de 4 instructions. Au-delà un processus est préempté par l'ordonnanceur.
Pour le reste...
Les soutenances auront lieu les vendredi 18 janvier 2008 et lundi 21 janvier 2008. Pour vous inscrire, rendez-vous au secrétariat, dans le bureau de Mme Maguy Eguienta. Les rapports seront rendus le jour de la soutenance. La soutenance durera une demi-heure. Tous les étudiants d'un groupe donné doivent être présents.