Machine virtuelle DIY

Parfois, une idée vient à l'esprit pour s'en débarrasser, ce qui est très difficile. Cela m'est arrivé.

J'ai décidé de créer une machine virtuelle (VM), étant donné qu'à l'époque je n'avais aucune idée, il me semblait que c'est une excellente idée. Si vous êtes intéressé, passez à la coupe!

Théorie


Tout d'abord, un peu de théorie. Qu'est-ce qu'une machine virtuelle en général? Il s'agit d'un programme ou d'un ensemble de programmes qui vous permet d'émuler une sorte de plate-forme matérielle, en d'autres termes, un émulateur d'ordinateur.

Les machines virtuelles elles-mêmes sont différentes, par exemple, Virtual Box est une machine virtuelle classique qui vous permet d'émuler un vrai ordinateur, mais par exemple, JVM (machine virtuelle Java) ne peut pas le faire.

Ma version de VM sera quelque peu similaire à la JVM simplement parce que c'est un projet plus de formation que destiné à créer une VM puissante.

La mémoire


Alors maintenant, essayons de comprendre la mémoire. Pour créer de la mémoire, j'ai décidé d'utiliser un tableau int non signé. La taille du tableau est déterminée à l'aide d'une macro, dans ma version la taille de la mémoire est de 4096 octets (il y a 1024 éléments dans le tableau, et puisque sur la plupart des plateformes 4 octets sont alloués pour les données int non signées, puis 1024 * 4 = 4096), entre autres, nous définirons 8 registres par 8 cellules dans chacune ce sera déjà 256 octets (8 * 8 * 4 = 256). Cela ressemble à ceci:

#define MEMSIZE 1024 unsigned int memory[MEMSIZE]; unsigned int reg[8][8]; 

Programmation


Nous avons de la mémoire, mais maintenant comment écrire du code pour notre VM? Maintenant, nous allons traiter ce problème, pour commencer, nous allons déterminer les commandes que notre machine exécutera:

 enum commands { /*   / List of commands */ CRG = 1, /* Change ReGister -   [1] */ CRC, /* Change Register Cell [2] */ PRG, /* Put in ReGister -       [3] */ PRC /* Put Register Cell     [4] */ }; 

Chaque équipe a son propre drapeau définissant des paramètres supplémentaires.
nous décrirons les drapeaux:

 enum flags { /*   / List of flags */ STDI = 1, /*   / Standard flag */ STDA /*   / Address flag */ }; 

La commande standard a la forme: [commande] [indicateur] [données] (l'apparence de certaines commandes peut différer), sur la base de cela, nous écrirons un interpréteur simple:

 if (memory[cell] == CRG && memory[cell + 1] == STDI) { indxX = memory[cell + 2]; cell++; } else if (memory[cell] == CRC && memory[cell + 1] == STDI) { indxY = memory[cell + 2]; cell++; } else if (memory[cell] == PRG && memory[cell + 1] == STDI) { reg[indxX][0] = memory[cell + 2]; cell++; } else if (memory[cell] == PRC && memory[cell + 1] == STDI) { reg[indxX][indxY] = memory[cell + 2]; cell++; } 

indxX & indxY sont des variables qui stockent la position actuelle du curseur dans le registre reg.
La cellule est une variable qui stocke la position actuelle du curseur dans le tableau de mémoire.

Mais la programmation avec des nombres n'est pas très pratique, donc en utilisant le préprocesseur C, nous décrirons notre assembleur. Je comprends qu'écrire asm avec des macros n'est pas très bon, mais cette solution est temporaire.

Notre code asm ressemble à ceci:

 /*  */ #define $CRG {memory[memIndx++] = CRG;} #define $CRC {memory[memIndx++] = CRC;} #define $PRG {memory[memIndx++] = PRG;} #define $PRC {memory[memIndx++] = PRC;} /*  */ #define _$STDI {memory[memIndx++] = STDI;} #define _$STDA {memory[memIndx++] = STDA;} /*  */ #define _$DATA memory[memIndx++] = 

memIndx est une variable stockant la position actuelle du curseur dans le tableau de mémoire.

Et voici le code sur notre asm mettant 123 dans le registre à l'adresse [1] [0] (premier registre, cellule zéro):

 $CRG /*   */ _$STDI /*   STDI */ _$DATA 1; /*   */ $CRC /*   */ _$STDI _$DATA 0; $PRC /*   */ _$STDI _$DATA 123; 

Félicitations, nous avons maintenant un semblant d'asme pour notre voiture!

Lancer des programmes


Nous avons réussi à faire exécuter des programmes à notre machine, mais le code manque de portabilité d'une machine à une autre, alors maintenant nous allons créer un générateur de code machine à partir de asm (et je vous rappelle que, contrairement aux vrais ordinateurs, notre machine a un code machine qui n'est pas présenté sous forme binaire, et nombres décimaux), en principe, ce n'est pas si difficile, mais d'abord, réfléchissons à l'implémentation.

D'abord, nous avons du code asm, maintenant nous devons le traduire en chiffres, puis écrire le code machine résultant dans un fichier .ncp (programme de code numérique, en fait c'est un fichier texte, mais pour le distinguer de tout le reste, j'ai trouvé ma propre extension), après cela nous devons exécuter le fichier .ncp, c'est simple à faire, puisque l'interpréteur que nous avons écrit plus tôt reconnaît les nombres, il nous suffit d'extraire les données du fichier et de les transformer en nombres en utilisant atoi ().

Passons des mots aux actes:

Lire le code et l'écrire dans un fichier:

 if (memory[i] == CRG && memory[i + 1] == STDI) { fprintf(code, "%d %d ", CRG, STDI); i++; } else if (memory[i] == CRC && memory[i + 1] == STDI) { fprintf(code, "%d %d ", CRC, STDI); i++; } else if (memory[i] == PRG && memory[i + 1] == STDI) { fprintf(code, "%d %d ", PRG, STDI); i++; } else if (memory[i] == PRC && memory[i + 1] == STDI) { fprintf(code, "%d %d ", PRC, STDI); i++; } 

Le code fait partie du corps de la fonction ncpGen ().

Lire un fichier et son exécution:

 if (prog != NULL) { fread(txt, 1, len, prog); tok = strtok(txt, " "); while (tok != NULL) { memory[i] = atoi(tok); tok = strtok(NULL, " "); if (argc == 3 && strcmp(argv[2], "-m") == 0) { printf("%d\n", memory[i]); } i++; } memInter(); } else { perror("Fail"); } 

Maintenant, définissons une macro pour qu'au lieu d'interpréter asm, le code se transforme en .ncp:

 #define _toNCP(name) {strcpy(filename, name);} {ncpGen();} 

Si quoi que ce soit, alors l'article ne présente pas tout le code, mais seulement une petite partie!

Le code complet se trouve dans le référentiel du projet.

Merci beaucoup d'avoir lu!

Source: https://habr.com/ru/post/fr442988/


All Articles