1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
\chapter{Partie assembleur}
\section{Assembleur}
\paragraph{}
L'assembleur que nous avons choisi de concevoir se décrit suivant le modèle ci-dessous:
\\
\includegraphics{Compilo.eps}
\paragraph{}
L'assembleur en lui-même est constitué de quatre parties distinctes:
\begin{itemize}
\item Le parser de code source assembleur. Il va lire le fichier source et effectuer les premiers
traitements nécessaires pour que l'analyseur syntaxique n'ait à traiter que des éléments simples.
\item Le méta parser du métalangage descriptif des instructions. Il sera exécuté au tout début
afin de créer les structures de données nécessaires à l'analyseur syntaxique.
\item L'analyseur syntaxique chargé d'effectuer la première phase de l'assemblage. Il va lire le
fichier source et va produire un premier "flux" binaire. Seules les instructions et les valeurs
immédiates seront encodées. Toutes les adresses seront laissées de coté.
\item Le solveur de symboles qui va effectuer la deuxième phase de l'assemblage. Il va simplement
lire le résultat de l'analyseur syntaxique et tenter de remplir tous les trous laissés par celui-ci.
\end{itemize}
La lecture du fichier est donc effectuée en une seule passe, sans besoin d'une quelconque relecture
ultérieure. Il s'agit donc d'un assembleur une passe. Les machines actuelles n'ont plus la
nécessité d'un assembleur deux passes car la puissance et la mémoire sont telles que le
programme peut être assemblé entièrement en mémoire. De plus, l'abstraction du microprocesseur
que nous simulons est suffisamment simple pour nous éviter les problèmes sur le calcul des adresses
en avant: en effet il n'existe qu'une seule forme d'adressage possible, alors que sur i386 par
exemple, un JMP en avant peut se coder sur 16, 24, 32 ou même 56 bits.
\paragraph{}
Nous avons choisi d'implémenter un système de métalangage servant à décrire les instructions
assembleur, ceci afin de servir deux buts:
\begin{itemize}
\item Alléger l'analyseur syntaxique.
\item Simplifier le travail d'une éventuelle évolution.
\end{itemize}
\paragraph{}
Ce système est très simple, et a été imaginé à partir du langage de programmation CAML. Il permet de
décrire le langage assembleur par "\textit{pattern}". Le méta langage supporte principalement quatre
types de définitions:
\begin{itemize}
\item la définition d'un champ de bits,
\item la définition d'une \textit{pattern},
\item la définition d'une instruction,
\item et la définition d'un phonème entre deux instructions.
\end{itemize}
\paragraph{}
L'assembleur en lui-même va lire le fichier texte en entrée, tenter de trouver une instruction qui
correspond à une des instructions décrites dans le méta langage, et créer le champ de bits décrit
dans le méta langage.
\paragraph{}
La sortie de l'assembleur est un fichier objet dont le format est quasiment identique à celui de
l'éditeur de liens, à la différence près qu'une table des symboles internes et externes est présente.
\paragraph{Encodage du fichier objet}
\subparagraph{}
Voici l'encodage du fichier objet:\\
\begin{center}
\begin{tabular}{|c|c|l|}
\hline
%il faut recentrer la ligne de titre pour la troisième colonne...
\textbf{Emplacement} & \textbf{Taille} & \textbf{Signification} \\
\hline
0 & 1 & Signature\footnotemark[1]\\
\hline
1 & 1 & Taille totale du fichier binaire\\
\hline
2 & 1 & Offset du point d'entrée du programme ($=-1$ si pas de point d'entrée)\\
\hline
3 & 1 & Taille de la partie \textit{text} $(=nb)$\\
\hline
4 & 1 & Taille des données statiques $(=ns)$\\
\hline
5 & 1 & Taille des données non initialisées\\
\hline
6 & 1 & Taille de la table des symboles $(=nr)$\\
\hline
7 & $nr$ & Table des symboles\\
\hline
$7+nr$ & $nb$ & Segment "\textit{text}"\\
\hline
$7+nr+nb$ & $ns$ & Segment des données statiques\\
\hline
\end{tabular}
\end{center}
\footnotetext[1]{Nous avons fixé la signature d'un fichier objet a : 0x4f424e4e.}
\subparagraph{}
Organisation de la table des symboles:\\
\begin{center}
\begin{tabular}{|c|c|l|}
\hline
\textbf{Emplacement} & \textbf{Taille} & \textbf{Signification} \\
\hline
0 & 1 & Nombre d'entrées\\
\hline
1 & $nr-1$ & Entrées\\
\hline
\end{tabular}
\end{center}
\subparagraph{}
Format d'une entrée:\\
\begin{center}
\begin{tabular}{|c|c|l|}
\hline
\textbf{Emplacement} & \textbf{Taille} & \textbf{Signification} \\
\hline
0 & 1 & Type du symbole\\
& & 0 = symbole interne de type \textit{text}\\
& & 1 = symbole externe de type \textit{text}\\
& & 2 = symbole interne de type \textit{data}\\
& & 3 = symbole externe de type \textit{data}\\
& & 4 = symbole interne de type \textit{bss}\\
\hline
1 & 1 & Décalage du symbole dans le segment de \textit{text}\\
\hline
2 & 1 & Taille du nom du symbole $(=st)$\\
\hline
3 & $st$ & Symbole\\
\hline
\end{tabular}
\end{center}
\subparagraph{}
Si un symbole est externe, alors le décalage indique l'endroit où il y est
fait référence. Il peut donc y avoir plusieurs symboles externes dans un même
fichier objet. Si un symbole est interne, alors le décalage indique son emplacement
soit dans le segment \textit{text}, soit dans le segment \textit{data}.
\section{Éditeur de liens}
L'éditeur de liens fonctionne selon un mode simple. Il va cumuler ensemble tous les
fichiers objets, en concaténant tous les segments \textit{text} et segments
\textit{data}, puis en remplaçant tous les symboles externes par leur valeur
correcte. Puis il produira un fichier exécutable comme défini à la
section~\ref{encodage_binaire}, page~\pageref{encodage_binaire}.
\section{MiniOS}
\paragraph{}
\label{MiniOS}
Pour pouvoir charger un binaire, effectuer le travail de relogement et effectuer
quelques travaux d'entrées/sorties avec le simulateur, nous avons besoin d'un
tout petit "système d'exploitation". Comme il ne s'agit pas de simuler un "vrai"
système d'exploitation, il sera programmé en C et non en langage d'assemblage.
Son utilité étant très limitée, nous n'avons pas besoin de créer quelque chose
de très complexe: quelques appels systèmes très simples seront mis en place pour
permettre les entrées/sorties\footnote{voir l'interface, section~\ref{Interface},
page~\pageref{Interface}}. Nous aurions pu intégrer directement ces fonctions
dans le code source C du simulateur, mais nous avons décidé de le dissocier du
module simulateur pour une éventuelle extension.
\paragraph{}
\label{relogement}
Le relogement effectué par le MiniOS fonctionne sur un principe très simple:
il va lire la table de relogement présente dans le fichier exécutable et pour
chaque entrée, il va rajouter l'offset auquel l'exécutable aura été chargé.
Ceci aura pour effet de reloger toutes les références absolues dans le code.
|