Composants de base du langage assembleur et de la structure des instructions. Format des données et structure des commandes du langage assembleur. Dans la discipline "Programmation système"

Introduction.

Le langage dans lequel le programme source est écrit s'appelle entrée langue, et la langue dans laquelle il est traduit pour exécution par le processeur est les jours de congé langue. Le processus de conversion de la langue d'entrée en langue de sortie est appelé diffuser.Étant donné que les processeurs sont capables d'exécuter des programmes en langage machine binaire, qui n'est pas utilisé pour la programmation, la traduction de tous les programmes sources est nécessaire. Connu deux façonsémissions : compilation et interprétation.

À compilation le programme source est d'abord entièrement traduit en un programme équivalent dans le langage de sortie, appelé objet programme puis exécuté. Ce processus est mis en œuvre à l'aide d'un spécial programmes, appelé compilateur. Un compilateur pour lequel le langage d'entrée est une forme symbolique de représentation du langage machine (de sortie) des codes binaires est appelé assembleur.

À interprétations Chaque ligne de texte du programme source est analysée (interprétée) et la commande qui y est spécifiée est immédiatement exécutée. La mise en œuvre de cette méthode est confiée à programme d'interprétation. L'interprétation prend beaucoup de temps. Pour augmenter son efficacité, au lieu de traiter chaque ligne, l'interpréteur convertit d'abord toutes les lignes. équipe chaînes en caractères (

). La séquence de symboles générée est utilisée pour exécuter les fonctions attribuées au programme d'origine.

Le langage assembleur décrit ci-dessous est implémenté à l’aide de la compilation.

Caractéristiques de la langue.

Principales fonctionnalités de l'assembleur :

● au lieu de codes binaires, le langage utilise des noms symboliques - mnémotechnique. Par exemple, pour la commande d'addition (

) des mnémoniques sont utilisés

Soustractions (

multiplications (

Divisions (

etc. Les noms symboliques sont également utilisés pour adresser les cellules mémoire. Pour programmer en langage assembleur, au lieu de codes et d'adresses binaires, il suffit de connaître les noms symboliques que l'assembleur traduit en codes binaires ;

chaque affirmation correspond une commande machine(code), c'est-à-dire qu'il existe une correspondance biunivoque entre les commandes de la machine et les opérateurs dans un programme en langage assembleur ;

● la langue donne accès à tous les objets et les équipes. Les langages de haut niveau n'ont pas cette capacité. Par exemple, le langage assembleur vous permet de vérifier les bits du registre des drapeaux et le langage de haut niveau (par exemple,

) n'a pas cette capacité. A noter que les langages de programmation système (par exemple C) occupent souvent une position intermédiaire. En termes d'accessibilité, ils sont plus proches du langage assembleur, mais ont la syntaxe d'un langage de haut niveau ;

● langage assembleur n'est pas une langue universelle. Chaque groupe spécifique de microprocesseurs possède son propre assembleur. Les langages de haut niveau n'ont pas cet inconvénient.

Contrairement aux langages de haut niveau, l’écriture et le débogage d’un programme en langage assembleur prennent beaucoup de temps. Malgré cela, le langage assembleur a reçu large utilisation en raison des circonstances suivantes :

● un programme écrit en langage assembleur est nettement plus petit et s'exécute beaucoup plus rapidement qu'un programme écrit en langage de haut niveau. Pour certaines applications, ces indicateurs jouent un rôle primordial, par exemple, de nombreux programmes système(y compris les compilateurs), programmes sur cartes de crédit, téléphones portables, pilotes de périphériques, etc. ;

● certaines procédures nécessitent accès total au matériel, ce qui est généralement impossible à faire dans un langage de haut niveau. Ce cas inclut les interruptions et les gestionnaires d'interruptions dans les systèmes d'exploitation, ainsi que les contrôleurs de périphériques dans les systèmes temps réel embarqués.

Dans la plupart des programmes, seul un petit pourcentage du code total est responsable d'un pourcentage important du temps d'exécution du programme. En règle générale, 1 % du programme est responsable de 50 % du temps d'exécution et 10 % du programme est responsable de 90 % du temps d'exécution. Par conséquent, pour écrire un programme spécifique dans des conditions réelles, on utilise à la fois l'assembleur et l'un des langages de haut niveau.

Format opérateur en langage assembleur.

Un programme en langage assembleur est une liste de commandes (instructions, phrases), dont chacune occupe une ligne distincte et contient quatre champs : un champ d'étiquette, un champ d'opération, un champ d'opérande et un champ de commentaire. Chaque champ a une colonne distincte.

Champ d’étiquette.

La colonne 1 est réservée au champ d'étiquette. L'étiquette est un nom symbolique, ou un identifiant, adresses mémoire. C'est nécessaire pour que vous puissiez :

● effectuer une transition conditionnelle ou inconditionnelle vers la commande ;

● accéder à l'emplacement où les données sont stockées.

Ces déclarations sont accompagnées d'une étiquette. Pour indiquer un nom, des lettres (majuscules) de l'alphabet anglais et des chiffres sont utilisés. Le nom doit avoir une lettre au début et un séparateur deux-points à la fin. L'étiquette deux-points peut être écrite sur une ligne séparée et l'opcode peut être écrit sur la ligne suivante de la colonne 2, ce qui simplifie le travail du compilateur. L'absence de deux points ne permet pas de distinguer un label d'un code opération s'ils sont situés sur des lignes distinctes.

Dans certaines versions du langage assembleur, les deux-points sont placés uniquement après les étiquettes d'instructions, pas après les étiquettes de données, et la longueur de l'étiquette peut être limitée à 6 ou 8 caractères.

Il ne doit pas y avoir de noms identiques dans le champ d'étiquette, puisque l'étiquette est associée aux adresses de commande. Si lors de l'exécution du programme il n'est pas nécessaire d'appeler une commande ou des données depuis la mémoire, alors le champ d'étiquette reste vide.

Champ du code d’opération.

Ce champ contient le code mnémonique d'une commande ou pseudo-commande (voir ci-dessous). Le code mnémonique de la commande est choisi par les développeurs du langage. En langage assembleur

le mnémonique est sélectionné pour charger un registre depuis la mémoire

), et pour sauvegarder le contenu du registre en mémoire - un mnémonique

). Dans les langages d'assemblage

pour les deux opérations, vous pouvez utiliser le même nom, respectivement

Si le choix des noms mnémoniques peut être arbitraire, alors la nécessité d'utiliser deux instructions machine est déterminée par l'architecture du processeur.

Les mnémoniques des registres dépendent également de la version de l'assembleur (Tableau 5.2.1).

Champ d'opérande.

Ici se trouve Informations Complémentaires, nécessaire pour effectuer l'opération. Dans le champ opérande des commandes de saut, l'adresse vers laquelle le saut doit être effectué est indiquée, ainsi que les adresses et les registres qui sont des opérandes pour la commande machine. A titre d'exemple, nous donnons des opérandes pouvant être utilisés pour les processeurs 8 bits

● des données numériques,

présentés dans différents systèmes numériques. Pour indiquer le système numérique utilisé, la constante est suivie de l'une des lettres latines : B,

En conséquence, les systèmes de nombres binaires, octaux, hexadécimaux et décimaux (

Vous n'êtes pas obligé de l'écrire). Si le premier chiffre d'un nombre hexadécimal est A, B, C,

Ensuite, un 0 (zéro) insignifiant est ajouté devant ;

● codes des registres internes du microprocesseur et des cellules mémoire

M (sources ou récepteurs d'informations) sous la forme des lettres A, B, C,

M ou leurs adresses dans n'importe quel système numérique (par exemple, 10B - adresse d'enregistrement

en système binaire);

● les identifiants,

pour enregistrer des paires d'avions,

Les premières lettres sont B,

N ; pour une paire d'accumulateurs et de registre de fonctionnalités -

; pour le compteur de programme -

;pour le pointeur de pile -

● des étiquettes indiquant les adresses des opérandes ou des instructions suivantes au conditionnel

(si la condition est remplie) et transitions inconditionnelles. Par exemple, l'opérande M1 dans la commande

signifie la nécessité d'une transition inconditionnelle vers la commande dont l'adresse dans le champ d'étiquette est marquée de l'identifiant M1 ;

● expressions,

qui sont construits en reliant les données discutées ci-dessus à l'aide d'opérateurs arithmétiques et logiques. Notez que la méthode de réservation de l'espace de données dépend de la version linguistique. Développeurs de langage d'assemblage pour

Définir le mot), puis entré plus tard Option alternative.

qui était dans le langage des processeurs dès le début

En version linguistique

utilisé

Définir une constante).

Les processeurs traitent des opérandes de différentes longueurs. Pour le définir, les développeurs assembleurs ont pris différentes décisions, par exemple :

Les registres II de différentes longueurs ont des noms différents : EAX - pour placer des opérandes de 32 bits (type

); AX - pour 16 bits (type

et AN - pour 8 bits (type

● pour les processeurs

Des suffixes sont ajoutés à chaque code opération : suffixe

Pour le type

; suffixe ".B" pour le type

différents opcodes sont utilisés pour des opérandes de différentes longueurs, par exemple pour charger un octet, un demi-mot (

) et des mots dans un registre de 64 bits à l'aide d'opcodes

respectivement.

Champ de commentaires.

Ce champ fournit des explications sur les actions du programme. Les commentaires n'affectent pas le fonctionnement du programme et sont destinés aux humains. Ils peuvent être nécessaires pour modifier un programme qui, sans ces commentaires, peut être totalement incompréhensible, même pour les programmeurs expérimentés. Un commentaire commence par un symbole et est utilisé pour expliquer et documenter les programmes. Le caractère de départ d'un commentaire peut être :

● point-virgule (;) dans les langues destinées aux processeurs de l'entreprise

Point d'exclamation(!) dans des langues pour

Chaque ligne de commentaire distincte est précédée d'un caractère de début.

Pseudo-commandes (directives).

En langage assembleur, il existe deux principaux types de commandes :

basique instructions qui sont l’équivalent du code machine du processeur. Ces commandes effectuent tous les traitements prévus par le programme ;

pseudo-commandes ou directives, conçu pour servir le processus de traduction d'un programme dans un langage de combinaison de codes. A titre d'exemple dans le tableau. 5.2.2 montre quelques pseudo-commandes de l'assembleur

pour la famille

.

Lors de la programmation, il existe des situations où, selon l'algorithme, la même chaîne de commandes doit être répétée plusieurs fois. Pour sortir de cette situation vous pouvez :

● écrivez la séquence de commandes requise chaque fois qu'elle apparaît. Cette approche conduit à une augmentation du volume du programme ;

● organiser cette séquence dans une procédure (sous-programme) et l'appeler si nécessaire. Cette sortie a ses inconvénients : il faut à chaque fois exécuter une commande spéciale d'appel de procédure et une commande de retour, qui, si la séquence est courte et fréquemment utilisée, peuvent réduire considérablement la vitesse du programme.

Le plus simple et méthode efficace la répétition répétée d'une chaîne de commandes consiste à utiliser macro, qui peut être représentée comme une pseudo-commande destinée à retraduire un groupe de commandes souvent rencontrées dans un programme.

Une macro, ou macrocommande, se caractérise par trois aspects : la macrodéfinition, la macroinversion et la macroextension.

Définition des macros

Il s'agit d'une désignation pour une séquence répétée de commandes de programme, utilisée comme référence dans le texte du programme.

La définition de la macro a la structure suivante :

Liste d'expressions ; Définition des macros

Dans la structure donnée de la macro-définition, trois parties peuvent être distinguées :

● titre

macro, y compris le nom

Pseudo-commande

et un ensemble de paramètres ;

● marqué de points corps macros ;

● équipe

l'obtention du diplôme

définitions de macros.

Le jeu de paramètres de définition de macro contient une liste de tous les paramètres donnés dans le champ d’opérande pour le groupe d’instructions sélectionné. Si ces paramètres ont été donnés plus tôt dans le programme, ils n'ont pas besoin d'être indiqués dans l'en-tête de définition de la macro.

Pour réassembler le groupe de commandes sélectionné, un appel composé du nom est utilisé

commandes de macro et liste de paramètres avec d’autres valeurs.

Lorsque l'assembleur rencontre une définition de macro pendant le processus de compilation, il la stocke dans la table de définition de macro. Lors d'apparitions ultérieures dans le programme du nom (

) d'une macro, l'assembleur le remplace par le corps de la macro.

L'utilisation d'un nom de macro comme opcode est appelée macro-inversion(appel de macro), et en le remplaçant par le corps de la macro - expansion macro.

Si un programme est représenté comme une séquence de caractères (lettres, chiffres, espaces, signes de ponctuation et retours chariot pour passer à une nouvelle ligne), alors l'expansion de macro consiste à remplacer certaines chaînes de cette séquence par d'autres chaînes.

L'expansion des macros se produit pendant le processus d'assemblage, et non pendant l'exécution du programme. Les méthodes de manipulation des chaînes de caractères sont affectées à macro signifie.

Le processus d'assemblage est effectué en deux passes :

● Lors du premier passage, toutes les définitions de macro sont conservées et les appels de macro sont développés. Dans ce cas, le programme d'origine est lu et converti en un programme dans lequel toutes les définitions de macro sont supprimées et chaque appel de macro est remplacé par le corps de la macro ;

● la deuxième passe traite le programme résultant sans macros.

Macros avec paramètres.

Pour travailler avec des séquences répétées de commandes, dont les paramètres peuvent prendre des valeurs différentes, des définitions de macros sont fournies :

● avec réel les paramètres placés dans le champ d'opérande de l'appel de macro ;

● avec officiel paramètres. Lors du développement d'une macro, chaque paramètre formel apparaissant dans le corps de la macro est remplacé par le paramètre réel correspondant.

en utilisant des macros avec des paramètres.

Le programme 1 contient deux séquences de commandes similaires, différant par le fait que la première échange P et

Et le deuxième

Le programme 2 comprend une macro avec deux paramètres formels P1 et P2. Lors du développement d'une macro, chaque caractère P1 dans le corps de la macro est remplacé par le premier paramètre réel (P,

), et le symbole P2 est remplacé par le deuxième paramètre réel (

) du programme n°1. Dans l'appel de macro

le programme 2 est marqué : P,

Le premier paramètre réel,

Deuxième paramètre réel.

Programme 1

Programme 2

MOUVEMENT EBX,Q MOUVEMENT EAX,Pl

MOUVEMENT Q,EAX MOUVEMENT EBX,P2

MOV P, EBX MOV P2, EAX

Capacités étendues.

Examinons quelques fonctionnalités avancées du langage

Si une macro contenant une commande de saut conditionnel et une étiquette vers laquelle accéder est appelée deux fois ou plus, l'étiquette sera dupliquée (problème d'étiquette en double), ce qui provoquera une erreur. Par conséquent, chaque appel attribue une étiquette distincte comme paramètre (par le programmeur). En langue

le label est déclaré local (

) et grâce à des fonctionnalités avancées, l'assembleur génère automatiquement une étiquette différente à chaque fois que la macro est développée.

vous permet de définir des macros à l'intérieur d'autres macros. Cette fonctionnalité avancée est très utile en combinaison avec la liaison conditionnelle d'un programme. Considérons

SI TAILLE DES MOTS GT 16 M2 MACRO

La macro M2 peut être définie dans les deux parties de l'instruction

Cependant, la définition dépend du processeur sur lequel le programme est assemblé : 16 bits ou 32 bits. Si M1 n’est pas appelé, alors la macro M2 ne sera pas définie du tout.

Une autre fonctionnalité avancée est que les macros peuvent appeler d'autres macros, y compris elles-mêmes - récursif appel. Dans ce dernier cas, pour éviter une boucle sans fin, la macro doit se passer un paramètre qui change à chaque expansion, et également vérifier ce paramètre et termine la récursion lorsque le paramètre atteint une certaine valeur.

Sur l'utilisation des moyens macro en assembleur.

Lors de l'utilisation de macros, l'assembleur doit être capable d'exécuter deux fonctions : enregistrer les définitions de macro Et élargir les défis macro.

Enregistrement des définitions de macro.

Tous les noms de macros sont stockés dans une table. Chaque nom est accompagné d'un pointeur vers la macro correspondante afin de pouvoir l'appeler si nécessaire. Certains assembleurs ont une table séparée pour les noms de macros, d'autres ont une table générale dans laquelle, avec les noms de macros, se trouvent toutes les instructions et directives machine.

Lorsque vous rencontrez une macro lors de l'assemblage est créé:

nouvel élément de tableau avec le nom de la macro, le nombre de paramètres et un pointeur vers une autre table de définition de macro où sera stocké le corps de la macro ;

● liste officiel paramètres.

Le corps de la macro, qui est simplement une chaîne de caractères, est ensuite lu et stocké dans la table de définition de macro. Les paramètres formels apparaissant dans le corps de la boucle sont marqués Caractère spécial.

Représentation interne d'une macro

de l'exemple ci-dessus pour le programme 2 (p. 244) est :

MOV EAX, MOV EBX, MOV MOV &

où le point-virgule est utilisé comme caractère de retour chariot et l'esperluette & est utilisée comme caractère de paramètre formel.

Extension des appels de macro.

Chaque fois qu'une définition de macro est rencontrée lors de l'assemblage, elle est stockée dans la table des macros. Lorsqu'une macro est appelée, l'assembleur arrête temporairement de lire les données d'entrée du périphérique d'entrée et commence à lire le corps de la macro stocké. Les paramètres formels extraits du corps de la macro sont remplacés par des paramètres réels et fournis par l'appel. L'esperluette & avant les paramètres permet à l'assembleur de les reconnaître.

Malgré le fait qu'il existe de nombreuses versions d'assembleur, les processus d'assemblage ont des caractéristiques communes et sont similaires à bien des égards. Le fonctionnement d’un assembleur à deux passes est discuté ci-dessous.

Assembleur en deux passes.

Un programme est constitué d'un certain nombre d'instructions. Par conséquent, il semblerait que lors de l'assemblage, vous puissiez utiliser la séquence d'actions suivante :

● le traduire en langage machine ;

● transférer le code machine obtenu dans un fichier et la partie correspondante du listing dans un autre fichier ;

● répétez les procédures répertoriées jusqu'à ce que l'intégralité du programme soit traduite.

Cependant, cette approche n'est pas efficace. Un exemple est le soi-disant problème lien de transfert. Si la première instruction est un saut vers l'instruction P, située à la toute fin du programme, alors l'assembleur ne peut pas la traduire. Il doit d'abord déterminer l'adresse de l'opérateur P, et pour ce faire il doit lire l'intégralité du programme. Chaque lecture complète du programme source est appelée passage. Montrons comment vous pouvez résoudre le problème du lien d'analyse en utilisant deux passes :

au premier passage, vous devriez collecter et stockez toutes les définitions de symboles (y compris les étiquettes) dans le tableau, et lors du deuxième passage, lisez et assemblez chaque opérateur. Cette méthode est relativement simple, mais un deuxième passage dans le programme d'origine nécessite du temps supplémentaire consacré aux opérations d'E/S ;

● au premier passage, vous devriez convertir le programme sous une forme intermédiaire et enregistrez-le dans un tableau, puis effectuez le deuxième passage non pas selon le programme d'origine, mais selon le tableau. Cette méthode d'assemblage permet de gagner du temps, puisque la deuxième passe n'effectue pas d'opérations d'E/S.

Premier passage.

But de la première passe- construire une table de symboles. Comme indiqué ci-dessus, un autre objectif de la première passe est de conserver toutes les définitions de macro et d'étendre les appels au fur et à mesure qu'ils apparaissent. Par conséquent, la définition des symboles et l’expansion des macros s’effectuent en une seule passe. Le symbole peut être soit étiquette, ou signification, auquel un nom spécifique est attribué à l'aide de la directive -you :

;Valeur - taille du tampon

En attribuant une signification aux noms symboliques dans le champ d'étiquette de commande, l'assembleur spécifie essentiellement les adresses que chaque commande aura lors de l'exécution du programme. A cet effet, l'assembleur stocke pendant le processus d'assemblage compteur d'adresses d'instruction(

) comme variable spéciale. Au début du premier passage, la valeur de la variable spéciale est définie sur 0 et est augmentée après chaque commande traitée de la longueur de cette commande. A titre d'exemple dans le tableau. 5.2.3 montre un fragment de programme indiquant la longueur des commandes et les valeurs du compteur. Au premier passage, les tables sont générées noms symboliques, directives Et codes d'opération, et si nécessaire littéral tableau. Un littéral est une constante pour laquelle l'assembleur réserve automatiquement de la mémoire. Notons immédiatement que les processeurs modernes contiennent des instructions avec des adresses immédiates, leurs assembleurs ne prennent donc pas en charge les littéraux.

Tableau des noms de symboles

contient un élément pour chaque nom (tableau 5.2.4). Chaque élément de la table des noms symboliques contient le nom lui-même (ou un pointeur vers celui-ci), sa valeur numérique et parfois des informations supplémentaires, qui peuvent inclure :

● la longueur du champ de données associé au symbole ;

● bits de réallocation de mémoire (qui indiquent si la valeur d'un symbole change si le programme est chargé à une adresse différente de celle prévue par l'assembleur) ;

● des informations indiquant si le symbole est accessible depuis l'extérieur de la procédure.

Les noms symboliques sont des étiquettes. Ils peuvent être spécifiés à l'aide d'opérateurs (par exemple,

Tableau directif.

Ce tableau répertorie toutes les directives, ou pseudo-commandes, rencontrées lors de l'assemblage d'un programme.

Tableau des codes d'opération.

Pour chaque code d'opération, le tableau comporte des colonnes distinctes : désignation du code d'opération, opérande 1, opérande 2, valeur hexadécimale du code d'opération, longueur de commande et type de commande (Tableau 5.2.5). Les codes d'opération sont divisés en groupes en fonction du nombre et du type d'opérandes. Le type de commande détermine le numéro de groupe et spécifie la procédure appelée pour traiter toutes les commandes de ce groupe.

Deuxième passage.

But de la deuxième passe- création d'un programme objet et impression, si nécessaire, du protocole d'assemblage ; afficher les informations nécessaires à l'éditeur de liens pour lier les procédures assemblées à différents moments en un seul fichier exécutable.

Lors de la deuxième passe (comme lors de la première), les lignes contenant les instructions sont lues et traitées une par une. L'opérateur d'origine et l'opérateur de sortie qui en dérive en hexadécimal objet Le code peut être imprimé ou placé dans un tampon pour une impression ultérieure. Après avoir réinitialisé le compteur d'adresses de commande, la commande est appelée déclaration suivante.

Le programme source peut contenir des erreurs, par exemple :

le symbole donné n'est pas défini ou est défini plusieurs fois ;

● l'opcode est représenté par un nom invalide (en raison d'une faute de frappe), n'a pas assez d'opérandes ou a trop d'opérandes ;

● aucun opérateur

Certains assembleurs peuvent détecter un symbole non défini et le remplacer. Cependant, dans la plupart des cas, lorsqu'il rencontre une instruction d'erreur, l'assembleur affiche un message d'erreur à l'écran et tente de poursuivre le processus d'assemblage.

Articles dédiés au langage assembleur.

UNIVERSITÉ NATIONALE D'OUZBÉKISTAN NOMME D'APRÈS MIRZO ULUGBEK

FACULTÉ DE TECHNOLOGIE INFORMATIQUE

Sur le sujet : Analyse sémantique d'un fichier EXE.

Complété:

Tachkent 2003.

Préface.

Langage d’assemblage et structure de commande.

Structure du fichier EXE (analyse sémantique).

Structure du fichier COM.

Le principe d'action et de propagation du virus.

Désassembleur.

Programmes.

Préface

Le métier de programmeur est étonnant et unique. De nos jours, il est impossible d’imaginer la science et la vie sans les dernières technologies. Tout ce qui touche à l'activité humaine ne peut se faire sans la technologie informatique. Et cela contribue à son développement et à sa perfection élevés. Bien que le développement des ordinateurs personnels ait commencé il n'y a pas si longtemps, des progrès colossaux ont été réalisés dans le domaine des produits logiciels et ces produits seront largement utilisés pendant longtemps. Le domaine des connaissances informatiques a connu une explosion, tout comme la technologie correspondante. Si l'on ne prend pas en compte l'aspect commercial, alors on peut dire qu'il n'y a pas d'étrangers dans ce domaine d'activité professionnelle. De nombreuses personnes développent des programmes non pas dans un but lucratif ou lucratif, mais de leur plein gré, par passion. Bien entendu, cela ne devrait pas affecter la qualité du programme, et dans ce secteur, pour ainsi dire, il existe une concurrence et une demande d'exécution de qualité, de travail stable et répondant à toutes les exigences modernes. Ici, il convient également de noter l'apparition des microprocesseurs dans les années 60, qui sont venus remplacer un grand nombre de jeux de lampes. Il existe certains types de microprocesseurs qui sont très différents les uns des autres. Ces microprocesseurs diffèrent les uns des autres par leur profondeur de bits et leurs commandes système intégrées. Les plus courants sont : Intel, IBM, Celeron, AMD, etc. Tous ces processeurs sont liés à l'architecture avancée des processeurs Intel. La diffusion des micro-ordinateurs a provoqué une reconsidération des attitudes à l'égard du langage assembleur pour deux raisons principales. Premièrement, les programmes écrits en langage assembleur nécessitent beaucoup moins de mémoire et de temps d’exécution. Deuxièmement, la connaissance du langage assembleur et du code machine qui en résulte permet de comprendre l'architecture de la machine, ce qui est peu susceptible d'être fourni lorsque l'on travaille dans un langage de haut niveau. Bien que la plupart des professionnels du logiciel développent dans des langages de haut niveau tels que Pascal, C ou Delphi, ce qui est plus facile lors de l'écriture de programmes, le plus puissant et le plus efficace logicielécrit entièrement ou partiellement en langage assembleur. Les langages de haut niveau ont été conçus pour éviter les caractéristiques techniques ordinateurs spécifiques. Et le langage assembleur, à son tour, est conçu pour les spécificités spécifiques du processeur. Par conséquent, afin d’écrire un programme en langage assembleur pour un ordinateur spécifique, vous devez connaître son architecture. De nos jours, la vue du principal produit logiciel est un fichier EXE. Considérant côtés positifs Cela signifie que l'auteur du programme peut avoir confiance en son intégrité. Mais c’est souvent loin d’être le cas. Il y a aussi un désassembleur. À l'aide d'un désassembleur, vous pouvez connaître les interruptions et les codes de programme. Il ne sera pas difficile pour une personne connaissant bien l'assembleur de refaire l'intégralité du programme à son goût. C’est peut-être là que surgit le problème le plus insoluble : le virus. Pourquoi les gens écrivent-ils un virus ? Certains posent cette question avec surprise, d'autres avec colère, mais il reste néanmoins des gens qui s'intéressent à cette tâche non pas dans l'optique de causer un préjudice, mais par intérêt pour la programmation système. Les virus sont écrits par raisons diverses. Certaines personnes aiment les appels système, d'autres améliorent leurs connaissances en assembleur. Je vais essayer d'expliquer tout cela dans mon travail de cours. Il indique également non seulement la structure du fichier EXE, mais également le langage assembleur.

^ Langage d'assemblage.

Il est intéressant de suivre, depuis l’apparition des premiers ordinateurs jusqu’à nos jours, la transformation des idées des programmeurs sur le langage assembleur.

Il était une fois, l’assembleur était un langage sans lequel on ne pouvait pas faire faire quoi que ce soit d’utile à un ordinateur. Petit à petit, la situation a changé. Des moyens plus pratiques de communication avec un ordinateur sont apparus. Mais contrairement à d'autres langages, l'assembleur n'est pas mort et, en principe, il ne pouvait pas le faire. Pourquoi? À la recherche d'une réponse, essayons de comprendre ce qu'est le langage assembleur en général.

En bref, le langage assembleur est une représentation symbolique du langage machine. Tous les processus d'une machine au niveau matériel le plus bas sont pilotés uniquement par des commandes (instructions) en langage machine. Il en ressort clairement que, malgré son nom commun, le langage assembleur est différent pour chaque type d'ordinateur. Ceci s'applique également apparence des programmes écrits en langage assembleur et des idées dont ce langage est le reflet.

Il est impossible de véritablement résoudre des problèmes liés au matériel (ou même d'ailleurs dépendants du matériel, comme l'augmentation de la vitesse d'un programme), sans connaissance en assembleur.

Un programmeur ou tout autre utilisateur peut utiliser n'importe quel outil de haut niveau, même des programmes pour construire des mondes virtuels, et peut-être même ne pas soupçonner qu'en fait l'ordinateur n'exécute pas les commandes du langage dans lequel son programme est écrit, mais leur représentation transformée sous la forme de séquences ennuyeuses et ennuyeuses de commandes provenant d'un langage complètement différent - le langage machine. Imaginons maintenant qu'un tel utilisateur ait un problème non standard ou que quelque chose ne fonctionne tout simplement pas. Par exemple, son programme doit fonctionner avec un appareil inhabituel ou effectuer d'autres actions nécessitant une connaissance des principes de fonctionnement du matériel informatique. Peu importe à quel point le programmeur est intelligent, quelle que soit la qualité du langage dans lequel il a écrit son merveilleux programme, il ne peut se passer de connaissances en assembleur. Et ce n'est pas un hasard si presque tous les compilateurs de langages de haut niveau contiennent des moyens de connecter leurs modules avec des modules assembleur ou prennent en charge l'accès au niveau de programmation assembleur.

Bien entendu, le temps des informaticiens généralistes est déjà révolu. Comme on dit, on ne peut pas embrasser l’immensité. Mais il y a quelque chose en commun, une sorte de fondement sur lequel repose toute formation informatique sérieuse. Il s'agit de connaissances sur les principes de fonctionnement d'un ordinateur, son architecture et son langage d'assemblage en tant que reflet et incarnation de ces connaissances.

Un ordinateur moderne typique (basé sur i486 ou Pentium) se compose des composants suivants (Figure 1).

Riz. 1. Ordinateur et périphériques

Riz. 2. Schéma fonctionnel ordinateur personnel

Sur la figure (Figure 1), on peut voir que l'ordinateur est composé de plusieurs périphériques physiques, chacun étant connecté à une unité, appelée unité système. Si nous réfléchissons logiquement, il est clair qu’il joue le rôle d’une sorte d’appareil de coordination. Regardons à l'intérieur de l'unité système (inutile d'essayer d'entrer dans le moniteur - il n'y a rien d'intéressant là-bas, et en plus, c'est dangereux) : ouvrez le boîtier et voyez quelques cartes, blocs, fils de connexion. Pour comprendre leur objectif fonctionnel, regardons le schéma fonctionnel d'un ordinateur typique (Fig. 2). Il ne prétend pas à une exactitude absolue et vise uniquement à montrer le but, l'interconnexion et la composition typique des éléments d'un ordinateur personnel moderne.

Discutons du diagramme de la Fig. 2 dans un style quelque peu non conventionnel.
Il est courant qu'une personne, lorsqu'elle rencontre quelque chose de nouveau, recherche des associations qui peuvent l'aider à comprendre l'inconnu. Quelles associations l’ordinateur évoque-t-il ? Par exemple, j’associe souvent un ordinateur à la personne elle-même. Pourquoi?

Lorsqu'une personne créait un ordinateur, quelque part au plus profond d'elle-même, elle pensait qu'elle créait quelque chose de semblable à elle-même. L'ordinateur dispose d'organes permettant de recevoir des informations du monde extérieur : un clavier, une souris et des lecteurs de disques magnétiques. En figue. 2 ces organes sont situés à droite des bus système. L'ordinateur possède des organes qui « digèrent » les informations reçues - ce sont CPU et RAM. Et enfin, l’ordinateur dispose d’organes vocaux qui produisent les résultats du traitement. Ce sont également quelques-uns des appareils sur la droite.

Ordinateurs modernes, bien sûr, est loin d’être humain. Ils peuvent être comparés à des créatures qui interagissent avec le monde extérieur au niveau d'un ensemble large mais limité de réflexes inconditionnés.
Cet ensemble de réflexes forme un système de commandes machine. Quel que soit le niveau de communication avec un ordinateur, cela se résume finalement à une séquence ennuyeuse et monotone de commandes machine.
Chaque commande de la machine est une sorte de stimulus destiné à exciter l'un ou l'autre réflexe inconditionné. La réaction à ce stimulus est toujours sans ambiguïté et « câblée » dans le bloc de microcommande sous la forme d'un microprogramme. Ce microprogramme met en œuvre des actions pour mettre en œuvre une commande machine, mais au niveau des signaux fournis à certains logique ordinateur, contrôlant ainsi divers sous-systèmes de l’ordinateur. C'est ce qu'on appelle le principe du contrôle par microprogramme.

Poursuivant l'analogie avec une personne, notons : pour qu'un ordinateur mange correctement, de nombreux systèmes d'exploitation, des compilateurs pour des centaines de langages de programmation, etc. ont été inventés. Mais tous ne sont en fait qu'un plateau sur lequel la nourriture (programmes) est livrée selon certaines règles.estomac (ordinateur). Seul l'estomac de l'ordinateur aime les régimes, les aliments monotones - donnez-lui des informations structurées, sous la forme de séquences de zéros et de uns strictement organisées, dont les combinaisons constituent le langage machine.

Ainsi, bien qu’en apparence polyglotte, l’ordinateur ne comprend qu’un seul langage : le langage des instructions machine. Bien sûr, pour communiquer et travailler avec un ordinateur, il n'est pas nécessaire de connaître ce langage, mais presque tous les programmeurs professionnels sont tôt ou tard confrontés à la nécessité de l'étudier. Heureusement, le programmeur n'a pas besoin d'essayer de comprendre la signification de diverses combinaisons de nombres binaires, puisque dans les années 50, les programmeurs ont commencé à utiliser un analogue symbolique du langage machine pour la programmation, appelé langage assembleur. Ce langage reflète fidèlement toutes les fonctionnalités du langage machine. C'est pourquoi, contrairement aux langages de haut niveau, le langage assembleur est différent pour chaque type d'ordinateur.

De tout ce qui précède, nous pouvons conclure que le langage assembleur étant « natif » pour un ordinateur, le programme le plus efficace ne peut y être écrit que (à condition qu'il soit écrit par un programmeur qualifié). Il y a un petit « mais » ici : il s'agit d'un processus très laborieux qui nécessite beaucoup d'attention et d'expérience pratique. Ainsi, en réalité, ils écrivent principalement des programmes en assembleur qui devraient fournir travail efficace avec du matériel. Parfois, des sections de programme critiques en termes de temps d'exécution ou de consommation de mémoire sont écrites en assembleur. Par la suite, ils sont formalisés sous forme de sous-programmes et combinés avec du code dans un langage de haut niveau.

Il est logique de commencer à apprendre le langage assembleur de n'importe quel ordinateur seulement après avoir découvert quelle partie de l'ordinateur reste visible et accessible pour la programmation dans ce langage. Il s'agit du modèle de programme informatique, dont une partie est le modèle de programme de microprocesseur, qui contient 32 registres, à un degré ou à un autre, disponibles pour être utilisés par le programmeur.

Ces registres peuvent être divisés en deux grands groupes :

^ 16 registres d'utilisateurs ;

16 registres système.

Les programmes en langage assembleur utilisent les registres de manière très intensive. La plupart des registres ont un objectif fonctionnel spécifique.

Comme leur nom l'indique, les registres d'utilisateurs sont appelés registres d'utilisateurs car le programmeur peut les utiliser lors de l'écriture de ses programmes. Ces registres comprennent (Fig. 3) :

Huit registres 32 bits pouvant être utilisés par les programmeurs pour stocker des données et des adresses (également appelés registres à usage général (GPR)) :

six registres de segments : cs, ds, ss, es, fs, gs ;

registres d’état et de contrôle :

Les drapeaux enregistrent les drapeaux/drapeaux ;

Le pointeur de commande enregistre eip/ip.

Riz. 3. Registres d'utilisateurs des microprocesseurs i486 et Pentium

Pourquoi bon nombre de ces registres sont-ils affichés avec des barres obliques ? Non, ce ne sont pas des registres différents – ils font partie d’un grand registre de 32 bits. Ils peuvent être utilisés dans le programme comme objets distincts. Cela a été fait pour garantir la fonctionnalité des programmes écrits pour les modèles 16 bits plus récents de microprocesseurs Intel, à commencer par le i8086. Les microprocesseurs i486 et Pentium possèdent principalement des registres 32 bits. Leur nombre, à l'exception des registres de segments, est le même que celui du i8086, mais la dimension est plus grande, ce qui se reflète dans leurs désignations - ils ont
préfixe e (étendu).

^ Registres à usage général
Tous les registres de ce groupe permettent d'accéder à leurs parties « inférieures » (voir Fig. 3). En regardant cette figure, notez que seules les parties inférieures de 16 et 8 bits de ces registres peuvent être utilisées pour l'auto-adressage. Les 16 bits supérieurs de ces registres ne sont pas disponibles en tant qu'objets indépendants. Cela a été fait, comme nous l'avons noté ci-dessus, pour des raisons de compatibilité avec les modèles 16 bits plus récents de microprocesseurs Intel.

Listons les registres appartenant au groupe des registres à usage général. Étant donné que ces registres sont physiquement situés dans le microprocesseur à l'intérieur d'une unité arithmétique et logique (ALU), ils sont également appelés registres ALU :

eax/ax/ah/al (registre d'accumulateur) - batterie.
Utilisé pour stocker des données intermédiaires. Certaines commandes nécessitent l'utilisation de ce registre ;

ebx/bx/bh/bl (registre de base) - registre de base.
Utilisé pour stocker l'adresse de base d'un objet en mémoire ;

ecx/cx/ch/cl (registre de comptage) - registre de compteur.
Utilisé dans les équipes qui effectuent des actions répétitives. Son utilisation est souvent implicite et cachée dans l'algorithme de la commande correspondante.
Par exemple, la commande pour organiser une boucle, en plus de transférer le contrôle à une commande située à une certaine adresse, analyse et diminue de un la valeur du registre ecx/cx ;

edx/dx/dh/dl (registre de données) - registre de données.
Tout comme le registre eax/ax/ah/al, il stocke les données intermédiaires. Dans certaines commandes, son utilisation est obligatoire ; Pour certaines commandes, cela se produit implicitement.

Les deux registres suivants sont utilisés pour prendre en charge les opérations dites en chaîne, c'est-à-dire les opérations qui traitent séquentiellement des chaînes d'éléments, dont chacune peut avoir une longueur de 32, 16 ou 8 bits :

esi/si (registre d'index source) - index source.
Ce registre en opérations chaînées contient l'adresse actuelle de l'élément dans la chaîne source ;

edi/di (registre d'index de destination) - index du destinataire (destinataire).
Ce registre en opérations chaînées contient l'adresse actuelle dans la chaîne de destination.

Dans l'architecture du microprocesseur, une structure de données telle qu'une pile est prise en charge au niveau matériel et logiciel. Pour travailler avec la pile, il existe des commandes spéciales dans le système d'instructions du microprocesseur, et dans le modèle logiciel du microprocesseur, il existe des registres spéciaux pour cela :

esp/sp (registre de pointeur de pile) - registre de pointeur de pile.
Contient un pointeur vers le haut de la pile dans le segment de pile actuel.

ebp/bp (Base Pointer Register) - registre de pointeur de base de trame de pile.
Conçu pour organiser l'accès aléatoire aux données à l'intérieur de la pile.

Une pile est une zone de programme permettant le stockage temporaire de données arbitraires. Bien entendu, les données peuvent également être stockées dans un segment de données, mais dans ce cas, pour chaque donnée temporairement stockée, une cellule mémoire nommée distincte doit être créée, ce qui augmente la taille du programme et le nombre de noms utilisés. La commodité de la pile réside dans le fait que sa zone est réutilisable, et le stockage des données sur la pile et leur récupération à partir de là se font à l'aide des commandes push et pop efficaces sans spécifier de nom.
La pile est traditionnellement utilisée, par exemple, pour sauvegarder le contenu des registres utilisés par un programme avant d'appeler un sous-programme qui, à son tour, utilisera les registres du processeur « à ses propres fins ». Le contenu original des registres est retiré de la pile après le retour du sous-programme. Une autre technique courante consiste à transmettre les paramètres requis à un sous-programme via la pile. Le sous-programme, sachant dans quel ordre les paramètres sont placés sur la pile, peut les récupérer et les utiliser lors de son exécution. Particularité La pile est un ordre unique dans lequel les données qu'elle contient sont récupérées : à un instant donné, seul l'élément supérieur est disponible sur la pile, c'est-à-dire l'élément le plus récemment poussé sur la pile. Retirer l'élément supérieur de la pile rend l'élément suivant disponible. Les éléments de la pile sont situés dans la zone mémoire allouée à la pile, en commençant par le bas de la pile (c'est-à-dire à partir de son adresse maximale) à des adresses décroissantes séquentiellement. L'adresse de l'élément supérieur accessible est stockée dans le registre de pointeur de pile SP. Comme toute autre zone de mémoire programme, la pile doit faire partie d'un segment ou former un segment distinct. Dans les deux cas, l'adresse de segment de ce segment est placée dans le registre de pile de segments SS. Ainsi, la paire de registres SS:SP décrit l'adresse d'une cellule de pile accessible : SS stocke l'adresse de segment de la pile, et SP stocke le décalage des dernières données stockées sur la pile (Fig. 4, a). Notez que dans l'état initial, le pointeur de pile SP pointe vers une cellule qui se trouve sous le bas de la pile et n'y est pas incluse.

Fig 4. Organisation de la pile : a - état initial, b - après le chargement d'un élément (dans cet exemple, le contenu du registre AX), c - après le chargement du deuxième élément (contenu du registre DS), d - après en avoir déchargé un élément, e - après avoir déchargé deux éléments et revenir à leur état d'origine.

Le chargement dans la pile est effectué par une commande spéciale pour travailler avec la pile (push). Cette instruction décrémente d'abord le contenu du pointeur de pile de 2 puis place l'opérande à l'adresse dans SP. Si, par exemple, nous voulons stocker temporairement le contenu du registre AX sur la pile, nous devons exécuter la commande

La pile passe dans l'état montré sur la Fig. 1.10, b. On peut voir que le pointeur de pile est décalé de deux octets vers le haut (vers des adresses inférieures) et que l'opérande spécifié dans la commande push est écrit à cette adresse. La commande de chargement de pile suivante est par exemple.

mettra la pile dans l’état montré sur la Fig. 1.10, ch. La pile stockera désormais deux éléments, et seul celui du haut, pointé par le pointeur de pile SP, sera accessible. Si après un certain temps nous avons besoin de restaurer le contenu original des registres stockés sur la pile, nous devons exécuter les commandes pop (push) pour décharger de la pile :

pop DS
pop hache

Quelle doit être la taille de la pile ? Cela dépend de l'intensité avec laquelle il est utilisé dans le programme. Si, par exemple, vous envisagez de stocker un tableau de 10 000 octets sur la pile, la pile doit avoir au moins cette taille. Il convient de garder à l'esprit que dans certains cas, la pile est automatiquement utilisée par le système, notamment lors de l'exécution de la commande d'interruption int 21h. Avec cette commande, le processeur pousse d'abord l'adresse de retour sur la pile, puis le DOS pousse le contenu des registres et d'autres informations liées au programme interrompu sur la pile. Par conséquent, même si un programme n’utilise pas du tout de pile, celle-ci doit quand même être présente dans le programme et avoir une taille d’au moins plusieurs dizaines de mots. Dans notre premier exemple, nous avons alloué 128 mots à la pile, ce qui est certainement suffisant.

^ Structure d'un programme assembleur

Un programme en langage assembleur est un ensemble de blocs de mémoire appelés segments de mémoire. Un programme peut être constitué d'un ou plusieurs de ces segments de bloc. Chaque segment contient une collection de phrases linguistiques, chacune occupant une ligne distincte de code de programme.

Il existe quatre types d'instructions assembleur :

commandes ou instructions qui sont des analogues symboliques des commandes de la machine. Au cours du processus de traduction, les instructions assembleur sont converties en commandes correspondantes du jeu d'instructions du microprocesseur ;

macrocommandes - phrases de texte de programme formatées d'une certaine manière, remplacées lors de la diffusion par d'autres phrases ;

directives, qui sont des instructions adressées au traducteur assembleur pour effectuer certaines actions. Les directives n’ont pas d’équivalent dans la représentation machine ;

lignes de commentaires contenant des caractères, y compris des lettres de l'alphabet russe. Les commentaires sont ignorés par le traducteur.

^ Syntaxe d'assemblage

Les phrases qui composent un programme peuvent être une construction syntaxique correspondant à une commande, une macro, une directive ou un commentaire. Pour que le traducteur assembleur les reconnaisse, ils doivent être formés selon certaines règles syntaxiques. Pour ce faire, il est préférable d’utiliser une description formelle de la syntaxe du langage, comme les règles de grammaire. Les manières les plus courantes de décrire un langage de programmation de cette manière sont les diagrammes syntaxiques et les formulaires Backus-Naur étendus. Pour utilisation pratique les diagrammes de syntaxe sont plus pratiques. Par exemple, la syntaxe des instructions du langage assembleur peut être décrite à l'aide des diagrammes de syntaxe présentés dans les figures suivantes.

Riz. 5. Format de phrase d'assemblage

Riz. 6. Format des directives

Riz. 7. Format des commandes et des macros

Sur ces images :

nom de l'étiquette - un identifiant dont la valeur est l'adresse du premier octet de la phrase dans le code source du programme qu'il désigne ;

name - un identifiant qui distingue cette directive des autres directives du même nom. Suite au traitement par l'assembleur d'une directive particulière, certaines caractéristiques peuvent être attribuées à ce nom ;

un code d'opération (OPC) et une directive sont des symboles mnémoniques pour l'instruction machine, la macro-instruction ou la directive de traduction correspondante ;

les opérandes font partie d'une commande, d'une macro ou d'une directive assembleur qui désignent les objets sur lesquels des actions sont effectuées. Les opérandes du langage assembleur sont décrits par des expressions avec des constantes numériques et textuelles, des étiquettes et des identifiants de variables utilisant des signes d'opérateur et quelques mots réservés.

^ Comment utiliser les diagrammes de syntaxe ? C'est très simple : il suffit de rechercher puis de suivre le chemin depuis l'entrée du diagramme (à gauche) jusqu'à sa sortie (à droite). Si un tel chemin existe, alors la phrase ou la construction est syntaxiquement correcte. S'il n'existe pas de tel chemin, le compilateur n'acceptera pas cette construction. Lorsque vous travaillez avec des diagrammes de syntaxe, faites attention au sens de parcours indiqué par les flèches, car parmi les chemins, certains peuvent être suivis de droite à gauche. Essentiellement, les diagrammes de syntaxe reflètent la logique du fonctionnement du traducteur lors de l'analyse des phrases d'entrée du programme.

Les caractères acceptables lors de l'écriture du texte du programme sont :

Tous des lettres: A-Z, a-z. Dans ce cas, les lettres majuscules et minuscules sont considérées comme équivalentes ;

Chiffres de 0 à 9 ;

Signes ?, @, $, _, &;

Séparateurs, . ()< > { } + / * % ! " " ? \ = # ^.

Les phrases en langage assembleur sont formées de lexèmes, qui sont des séquences syntaxiquement inséparables de symboles linguistiques valides qui ont un sens pour le traducteur.

Les lexèmes sont :

les identifiants sont des séquences de caractères valides utilisées pour désigner des objets de programme tels que des codes d'opération, des noms de variables et des noms d'étiquettes. La règle d'écriture des identifiants est la suivante : un identifiant peut être constitué d'un ou plusieurs caractères. Comme symboles, vous pouvez utiliser des lettres de l'alphabet latin, des chiffres et certains caractères spéciaux - _, ?, $, @. Un identifiant ne peut pas commencer par un caractère numérique. La longueur de l'identifiant peut aller jusqu'à 255 caractères, bien que le traducteur n'accepte que les 32 premiers et ignore le reste. Vous pouvez ajuster la longueur des identifiants possibles à l'aide de l'option ligne de commande mv. De plus, il est possible de demander au traducteur de faire la distinction entre les lettres majuscules et minuscules ou d'ignorer leur différence (ce qui est fait par défaut).

^Commandes d'assembleur.

Les commandes de l'assembleur révèlent la possibilité de transférer vos exigences vers l'ordinateur, un mécanisme de transfert de contrôle dans un programme (cycles et transitions) pour des comparaisons logiques et l'organisation du programme. Cependant, les tâches programmables sont rarement aussi simples. La plupart des programmes contiennent une série de boucles dans lesquelles plusieurs commandes sont répétées jusqu'à ce qu'une certaine exigence soit atteinte, ainsi que diverses vérifications qui déterminent laquelle des actions doit être effectuée. Certaines instructions peuvent transférer le contrôle en modifiant la séquence normale d'étapes en modifiant directement la valeur de décalage dans le pointeur d'instruction. Comme mentionné précédemment, il existe différentes commandes pour différents processeurs, mais nous examinerons un certain nombre de commandes pour les processeurs 80186, 80286 et 80386.

Pour décrire l'état des drapeaux après l'exécution d'une certaine commande, nous utiliserons une sélection dans un tableau reflétant la structure du registre des drapeaux eflags :

La ligne du bas de ce tableau montre les valeurs des indicateurs après l'exécution de la commande. Les notations suivantes sont utilisées :

1 - une fois la commande exécutée, le drapeau est défini (égal à 1) ;

0 - après l'exécution de la commande, le drapeau est réinitialisé (égal à 0) ;

r - la valeur du drapeau dépend du résultat de la commande ;

Une fois la commande exécutée, l'indicateur n'est pas défini ;

espace - une fois la commande exécutée, le drapeau ne change pas ;

La notation suivante est utilisée pour représenter les opérandes dans les diagrammes syntaxiques :

r8, r16, r32 - un opérande dans l'un des registres de taille d'octet, de mot ou de double mot ;

m8, m16, m32, m48 - taille de l'opérande mémoire en octets, mot, double mot ou 48 bits ;

i8, i16, i32 - taille d'opérande immédiate, octet, mot ou double mot ;

a8, a16, a32 - adresse relative (offset) dans le segment de code.

Commandes (par ordre alphabétique) :

*Ces commandes sont décrites en détail.

AJOUTER
(Ajout)

Ajout

^ Schéma de commande :

ajouter une destination, une source

Objectif : ajout de deux opérandes source et destination de taille octet, mot ou double mot.

Algorithme de travail :

ajoutez les opérandes source et destination ;

écrire le résultat de l'addition au récepteur ;

poser des drapeaux.

Etat des flags après exécution de la commande :

Application:
La commande add est utilisée pour ajouter deux opérandes entiers. Le résultat de l'addition est placé à l'adresse du premier opérande. Si le résultat de l'addition dépasse les limites de l'opérande du récepteur (un débordement se produit), alors cette situation doit être prise en compte en analysant le drapeau cf et l'utilisation ultérieure éventuelle de la commande adc. Par exemple, ajoutons les valeurs dans le registre ax et la zone mémoire ch. Lors de l'ajout, tenez compte de la possibilité de débordement.

Registre plus registre ou mémoire :

|000000dw|modregr/rm|

Registre AX (AL) plus valeur immédiate :

|0000010w|--data--|data si w=1|

Registre ou mémoire plus valeur immédiate :

|100000sw|mod000r/m|--data--|data si BW=01|

APPEL
(APPEL)

Appel d'une procédure ou d'une tâche

^ Schéma de commande :

But:

transférer le contrôle vers une procédure proche ou lointaine avec stockage de l'adresse du point de retour sur la pile ;

changer de tâche.

Algorithme de travail :
déterminé par le type d'opérande :

Near label - le contenu du pointeur de commande eip/ip est poussé sur la pile et la nouvelle valeur d'adresse correspondant à l'étiquette est chargée dans le même registre ;

Étiquette Far - le contenu du pointeur de commande eip/ip et cs est poussé sur la pile. Ensuite, de nouvelles valeurs d'adresse correspondant à l'étiquette lointaine sont chargées dans les mêmes registres ;

R16, 32 ou m16, 32 - définissent un registre ou une cellule mémoire contenant des décalages dans le segment d'instruction actuel auquel le contrôle est transféré. Lorsque le contrôle est transféré, le contenu du pointeur de commande eip/ip est poussé sur la pile ;

Pointeur mémoire - définit un emplacement mémoire contenant un pointeur de 4 ou 6 octets vers la procédure appelée. La structure d'un tel pointeur est de 2+2 ou 2+4 octets. L'interprétation d'un tel pointeur dépend du mode de fonctionnement du microprocesseur :

^ État des drapeaux après l'exécution de la commande (sauf changement de tâche) :

l'exécution de la commande n'affecte pas les drapeaux

Lorsqu'une tâche est commutée, les valeurs des indicateurs sont modifiées en fonction des informations sur le registre eflags dans le segment d'état TSS de la tâche vers laquelle la tâche est basculée.
Application:
La commande d'appel permet d'organiser un transfert de contrôle flexible et multivariant vers un sous-programme tout en préservant l'adresse du point de retour.

Code objet (quatre formats) :

Adressage direct dans un segment :

|11101000|disp-bas|diep-haut|

Adressage indirect dans un segment :

|11111111|mod010r/m|

Adressage indirect entre segments :

|11111111|mod011r/m|

Adressage direct entre segments :

|10011010|offset-low|offset-high|seg-low|seg-high|

CMP
(Opérandes Comparer)

Comparaison d'opérandes

^ Schéma de commande :

cmp opérande1, opérande2

Objectif : comparaison de deux opérandes.

Algorithme de travail :

effectuer une soustraction (opérande1-opérande2);

en fonction du résultat, définissez les indicateurs, ne modifiez pas l'opérande1 et l'opérande2 (c'est-à-dire ne vous souvenez pas du résultat).

Application:
Cette commande utilisé pour comparer deux opérandes par soustraction sans changer les opérandes. En fonction des résultats de la commande, des indicateurs sont définis. La commande cmp est utilisée avec les commandes de saut conditionnel et la commande set byte by value setcc.

Code objet (trois formats) :

Registre ou mémoire avec registre :

|001110dw|modregr/m|

Valeur immédiate avec registre AX (AL) :

|0011110w|--data--|données si w=1|

Valeur immédiate avec registre ou mémoire :

|100000sw|mod111r/m|--data--|data si sw=0|

DÉC
(Opérande DECrement de 1)

Diminuer un opérande de un

^ Schéma de commande :

opérande de décembre

Objectif : Diminuer la valeur d'un opérande en mémoire ou dans un registre de 1.

Algorithme de travail :
la commande soustrait 1 de l’opérande. Etat des flags après exécution de la commande :

Application:
L'instruction dec est utilisée pour décrémenter la valeur d'un octet, d'un mot, d'un double mot en mémoire ou d'un registre de un. Notez cependant que la commande n’affecte pas l’indicateur cf.

S'inscrire : |01001reg|

^ Registre ou mémoire : |1111111w|mod001r/m|

DIV
(DIVide non signé)

Division non signée

Aperçu de l'équipe :

diviseur div

Objectif : Effectuer une opération de division entre deux valeurs binaires non signées.

^ Algorithme de fonctionnement :
La commande nécessite deux opérandes : le dividende et le diviseur. Le dividende est spécifié implicitement et sa taille dépend de la taille du diviseur, qui est spécifiée dans la commande :

si le diviseur a une taille d'octet, alors le dividende doit être situé dans le registre hache. Après l'opération, le quotient est placé dans al et le reste dans ah ;

si le diviseur a la taille d'un mot, alors le dividende doit être situé dans la paire de registres dx:ax, la partie d'ordre inférieur du dividende étant située dans ax. Après l'opération, le quotient est placé en hache et le reste en dx ;

si le diviseur est un double mot, alors le dividende doit être situé dans la paire de registres edx:eax, la partie d'ordre inférieur du dividende étant située dans eax. Après l'opération, le quotient est placé dans eax et le reste dans edx.

^ État des drapeaux après l'exécution de la commande :

Application:
La commande effectue une division entière des opérandes, produisant le résultat de la division comme le quotient et le reste de la division. Lors de l'exécution d'une opération de division, une exception peut se produire : 0 - erreur de division. Cette situation se produit dans l'un des deux cas suivants : le diviseur est 0 ou le quotient est trop grand pour tenir dans le registre eax/ax/al.

Code objet:

|1111011w|mod110r/m|

INT
(Interrompre)

Appel de la routine du service d'interruption

^ Schéma de commande :

int numéro_interruption

Objectif : appeler la routine de service d'interruption avec le numéro d'interruption spécifié par l'opérande de commande.

^ Algorithme de fonctionnement :

poussez les drapeaux, enregistrez les eflags/flags et l'adresse de retour sur la pile. Lors de l'écriture d'une adresse de retour, le contenu du registre de segments cs est écrit en premier, puis le contenu du pointeur de commande eip/ip ;

remettre les indicateurs if et tf à zéro ;

transférer le contrôle au programme de service d'interruption avec le numéro spécifié. Le mécanisme de transfert de contrôle dépend du mode de fonctionnement du microprocesseur.

^ État des drapeaux après l'exécution de la commande :

Application:
Comme vous pouvez le voir d'après la syntaxe, il existe deux formes de cette commande :

int 3 - possède son propre code d'opération individuel 0cch et occupe un octet. Cette circonstance rend très pratique l'utilisation dans divers débogueurs de logiciels pour définir des points d'arrêt en remplaçant le premier octet de n'importe quelle commande. Le microprocesseur, rencontrant une commande avec le code opération 0cch dans la séquence de commandes, appelle le programme de traitement des interruptions avec le vecteur numéro 3, qui sert à communiquer avec le débogueur logiciel.

La deuxième forme de commande occupe deux octets, a un opcode de 0cdh et vous permet de lancer un appel à une routine de service d'interruption avec un numéro de vecteur compris entre 0 et 255. Comme indiqué, les caractéristiques du transfert de contrôle dépendent du mode de fonctionnement du microprocesseur.

Code objet (deux formats) :

S'inscrire : |01000reg|

^ Registre ou mémoire : |1111111w|mod000r/m|

J.C.C.
JCXZ/JECXZ
(Sauter si condition)

(Sauter si CX=Zéro/Sauter si ECX=Zéro)

Sauter si la condition est remplie

Sauter si CX/ECX est nul

^ Schéma de commande :

étiquette jcc
étiquette jcxz
étiquette jecxz

Objectif : transition au sein du segment de commande actuel en fonction de certaines conditions.

^ Algorithme de commande (sauf jcxz/jecxz) :
Vérification de l'état des drapeaux en fonction de l'opcode (cela reflète la condition vérifiée) :

si la condition testée est vraie, alors allez dans la cellule indiquée par l'opérande ;

si la condition vérifiée est fausse, transférez le contrôle à la commande suivante.

Algorithme pour la commande jcxz/jecxz :
Vérification de la condition que le contenu du registre ecx/cx soit égal à zéro :

si la condition est vérifiée

Structure des commandes en langage assembleur La programmation au niveau des commandes machine est le niveau minimum auquel la programmation informatique est possible. Le système de commande de la machine doit être suffisant pour mettre en œuvre les actions requises en donnant des instructions à l'équipement de la machine. Chaque instruction machine se compose de deux parties : une partie opérationnelle, qui détermine « quoi faire » et un opérande, qui détermine les objets de traitement, c'est-à-dire « quoi faire ». Une instruction machine à microprocesseur, écrite en langage assembleur, est une ligne unique qui a la forme suivante : opérande(s) de commande/directive d'étiquette ; commentaires L'étiquette, la commande/directive et l'opérande sont séparés par au moins un espace ou un caractère de tabulation. Les opérandes de la commande sont séparés par des virgules.

Structure des commandes du langage assembleur Une commande assembleur indique au traducteur quelle action le microprocesseur doit effectuer. Les directives d'assemblage sont des paramètres spécifiés dans le texte du programme qui affectent le processus d'assemblage ou les propriétés du fichier de sortie. L'opérande précise la valeur initiale des données (dans le segment de données) ou des éléments sur lesquels l'action de commande est effectuée (dans le segment de code). Une instruction peut avoir un ou deux opérandes, ou aucun opérande. Le nombre d'opérandes est implicitement spécifié par le code instruction. Si une commande ou une directive doit être continuée sur la ligne suivante, le caractère barre oblique inverse est utilisé : "" . Par défaut, l'assembleur ne fait pas la distinction entre les lettres majuscules et minuscules lors de l'écriture des commandes et des directives. Exemples de directives et de commandes Count db 1 ; Nom, directive, un opérande mov eax, 0 ; Commande, deux opérandes

Les identifiants sont des séquences de caractères valides utilisées pour désigner les noms de variables et les noms d'étiquettes. L'identifiant peut être constitué d'un ou plusieurs des caractères suivants : toutes les lettres de l'alphabet latin ; nombres de 0 à 9 ; caractères spéciaux : _, @, $, ? . Un point peut être utilisé comme premier caractère de l'étiquette. Les noms d'assembleur réservés (directives, opérateurs, noms de commandes) ne peuvent pas être utilisés comme identifiants. Le premier caractère de l'identifiant doit être une lettre ou un caractère spécial. Longueur maximale L'identifiant comporte 255 caractères, mais le traducteur accepte les 32 premiers et ignore le reste. Toutes les étiquettes écrites sur une ligne qui ne contient pas de directive assembleur doivent se terminer par deux points : :. L'étiquette, la commande (directive) et l'opérande ne doivent pas nécessairement commencer à une position particulière dans la ligne. Il est recommandé de les écrire dans une colonne pour une plus grande lisibilité du programme.

Étiquettes Toutes les étiquettes écrites sur une ligne ne contenant pas de directive assembleur doivent se terminer par deux points : :. L'étiquette, la commande (directive) et l'opérande ne doivent pas nécessairement commencer à une position particulière dans la ligne. Il est recommandé de les écrire dans une colonne pour une plus grande lisibilité du programme.

Commentaires L'utilisation de commentaires dans un programme améliore sa clarté, en particulier lorsque le but d'un ensemble de commandes n'est pas clair. Les commentaires commencent sur n'importe quelle ligne du module source par un point-virgule (;). Tous les caractères à droite de " ; " à la fin de la ligne se trouve un commentaire. Un commentaire peut contenir n'importe quel caractère imprimable, y compris l'espace. Un commentaire peut s'étendre sur toute la ligne ou suivre une commande sur la même ligne.

Structure du programme en langage assembleur Un programme écrit en langage assembleur peut être constitué de plusieurs parties appelées modules, dont chacune peut définir un ou plusieurs segments de données, de pile et de code. Tout programme complet en langage assembleur doit inclure un module principal, ou module principal, à partir duquel commence son exécution. Le module peut contenir segments de programme, les segments de données et de pile déclarés à l'aide des directives appropriées.

Modèles de mémoire Avant de déclarer des segments, vous devez spécifier le modèle de mémoire à l'aide d'une directive. Modificateur MODEL memory_model, call_convention, OS_type, stack_parameter Modèles de mémoire de base du langage assembleur : modèle de mémoire Adressage de code Adressage de données système opérateur Entrelacement de code et de données PETIT PROCHE MS-DOS Acceptable PETIT PROCHE MS-DOS, Windows Non MOYEN LOIN PROCHE MS-DOS, Windows Non COMPACT PROCHE LOIN MS-DOS, Windows Non GRAND LOIN MS-DOS, Windows Non ÉNORME LOIN MS-DOS, Windows Non PRES de Windows 2000, Windows XP, Windows Acceptable PLAT PRES de NT,

Modèles de mémoire Le petit modèle ne fonctionne que dans les applications MS-DOS 16 bits. Dans ce modèle, toutes les données et tous les codes sont situés sur un seul segment physique. Dans ce cas, la taille du fichier programme ne dépasse pas 64 Ko. Le petit modèle prend en charge un segment de code et un segment de données. Les données et le code sont traités au plus près lors de l'utilisation de ce modèle. Le modèle moyen prend en charge plusieurs segments de code et un segment de données, toutes les références dans les segments de code étant considérées comme éloignées par défaut et les références dans un segment de données considérées comme proches. Le modèle compact prend en charge plusieurs segments de données qui utilisent l'adressage de données lointaines (loin) et un segment de code qui utilise l'adressage proche (proche). Le grand modèle prend en charge plusieurs segments de code et plusieurs segments de données. Par défaut, toutes les références au code et aux données sont considérées comme loin. Le modèle énorme est presque équivalent au modèle à grande mémoire.

Modèles de mémoire Le modèle plat suppose une configuration de programme non segmentée et est utilisé uniquement dans les systèmes d'exploitation 32 bits. Ce modèle est similaire au modèle minuscule dans la mesure où les données et le code sont situés dans un seul segment, mais il est de 32 bits. Développer un programme pour le modèle plat avant la directive. l'appartement modèle doit placer l'une des directives : . 386, . 486, . 586 ou. 686. Le choix de la directive de sélection du processeur détermine l'ensemble des instructions disponibles lors de l'écriture des programmes. La lettre p après la directive de sélection du processeur signifie mode de fonctionnement protégé. L'adressage des données et du code est proche, toutes les adresses et pointeurs étant en 32 bits.

Modèles de mémoire. Modificateur MODEL memory_model, call_convention, OS_type, stack_parameter Le paramètre modificateur est utilisé pour définir les types de segments et peut prendre les valeurs suivantes : utiliser 16 (les segments du modèle sélectionné sont utilisés en 16 bits) utiliser 32 (les segments du modèle sélectionné sont utilisés comme 32 bits). Le paramètre call_convention est utilisé pour déterminer la méthode de transmission des paramètres lors de l'appel d'une procédure depuis d'autres langages, y compris les langages de haut niveau (C++, Pascal). Le paramètre peut prendre les valeurs suivantes : C, BASIC, FORTRAN, PASCAL, SYSCALL, STDCALL.

Modèles de mémoire. Modificateur MODEL memory_model, call_convention, OS_type, stack_parameter Le paramètre OS_type est OS_DOS par défaut, et sur ce moment c'est la seule valeur prise en charge pour ce paramètre. Le paramètre stack_parameter est défini sur : NEARSTACK (le registre SS est égal à DS, les zones de données et de pile sont situées dans le même segment physique) FARSTACK (le registre SS n'est pas égal à DS, les zones de données et de pile sont situées dans des segments physiques différents). La valeur par défaut est NEARSTACK.

Un exemple de programme qui ne fait rien. 686 P. MODÈLE PLAT, STDCALL. DONNÉES. CODE START: RET END START RET - commande du microprocesseur. Il garantit que le programme se termine correctement. La suite du programme concerne le fonctionnement du traducteur. . 686 P - Les commandes en mode protégé du Pentium 6 (Pentium II) sont autorisées. Cette directive sélectionne l'ensemble d'instructions assembleur pris en charge, indiquant le modèle de processeur. . MODÈLE FLAT, stdcall - modèle à mémoire plate. Ce modèle de mémoire est utilisé dans le système d'exploitation Windows. stdcall - la convention d'appel de procédure utilisée.

Un exemple de programme qui ne fait rien. 686 P. MODÈLE PLAT, STDCALL. DONNÉES. CODE DÉBUT : RET FIN DÉBUT. DATA est un segment de programme contenant des données. Ce programme n'utilise pas la pile, donc le segment. La PILE est manquante. . CODE est un segment de programme contenant du code. DÉBUT - étiquette. END START - la fin du programme et un message au compilateur indiquant que l'exécution du programme doit commencer par l'étiquette START. Chaque programme doit contenir une directive END pour marquer la fin code source programmes. Toutes les lignes qui suivent la directive END sont ignorées. L'étiquette spécifiée après la directive END indique au traducteur le nom du module principal à partir duquel l'exécution du programme commence. Si le programme contient un module, l'étiquette après la directive END peut être omise.

Traducteurs en langage d'assemblage Traducteur - programme ou moyens techniques, qui convertit un programme représenté dans l'un des langages de programmation en un programme dans le langage cible, appelé code objet. En plus de prendre en charge les mnémoniques d'instructions machine, chaque traducteur possède son propre ensemble de directives et de macro-outils, souvent incompatibles avec quoi que ce soit d'autre. Les principaux types de traducteurs de langage assembleur : MASM (Microsoft Assembler), TASM (Borland Turbo Assembler), FASM (Flat Assembler) - un assembleur multi-passes distribué gratuitement écrit par Tomasz Gryshtar (polonais), NASM (Netwide Assembler) - un assembleur pour l'architecture Intel x 86, a été créé par Simon Tatham avec Julian Hall et est actuellement développé par une petite équipe de développeurs chez Source. Forger. filet.

Src="https://present5.com/presentation/-29367016_63610977/image-15.jpg" alt="Traduction d'un programme dans Microsoft Visual Studio 2005 1) Créez un projet en sélectionnant Fichier->Nouveau- >Menu Projet Et"> Трансляция программы в Microsoft Visual Studio 2005 1) Создать проект, выбрав меню File->New->Project и указав имя проекта (hello. prj) и тип проекта: Win 32 Project. В дополнительных опциях мастера проекта указать “Empty Project”.!}

Src="https://present5.com/presentation/-29367016_63610977/image-16.jpg" alt="Traduction du programme dans Microsoft Visual Studio 2005 2) Dans l'arborescence du projet (Affichage->Explorateur de solutions) ajouter"> Трансляция программы в Microsoft Visual Studio 2005 2) В дереве проекта (View->Solution Explorer) добавить файл, в котором будет содержаться текст программы: Source. Files->Add->New. Item.!}

Traduction du programme dans Microsoft Visual Studio 2005 3) Sélectionnez le type de fichier Code C++, mais spécifiez le nom avec l'extension. asme :

Traduction du programme dans Microsoft Visual Studio 2005 5) Définissez les paramètres du compilateur. Cliquez avec le bouton droit sur le menu Règles de construction personnalisées dans le fichier de projet...

Traduisez le programme dans Microsoft Visual Studio 2005 et sélectionnez Microsoft Macro Assembler dans la fenêtre qui apparaît.

Traduction du programme dans Microsoft Visual Studio 2005 Vérifiez avec le bouton droit dans le fichier bonjour. asm du menu Propriétés et installez Général->Outil : Microsoft Macro Assembler.

Src="https://present5.com/presentation/-29367016_63610977/image-22.jpg" alt="Traduction du programme dans Microsoft Visual Studio 2005 6) Compilez le fichier en sélectionnant Build->Build hello. prj."> Трансляция программы в Microsoft Visual Studio 2005 6) Откомпилировать файл, выбрав Build->Build hello. prj. 7) Запустить программу, нажав F 5 или выбрав меню Debug->Start Debugging.!}

Programmation sous Windows La programmation sous Windows est basée sur l'utilisation de fonctions API (Application Program Interface, c'est-à-dire interface d'application logicielle). Leur nombre atteint 2000. Le programme Windows se compose en grande partie de tels appels. Toutes les interactions avec appareils externes et les ressources du système d'exploitation se produisent, en règle générale, via de telles fonctions. salle d'opération Système Windows utilise un modèle de mémoire plate. L'adresse de toute cellule mémoire sera déterminée par le contenu d'un registre de 32 bits. Il existe 3 types de structures de programme pour Windows : boîte de dialogue (la fenêtre principale est une boîte de dialogue), structure console ou sans fenêtre, structure classique (fenêtrée, cadre).

Appel Fonctions Windows API Dans le fichier d'aide, toute fonction API est présentée comme type nom_fonction (FA 1, FA 2, FA 3) Type – type de valeur de retour ; FAx – une liste d'arguments formels dans l'ordre dans lequel ils apparaissent. Par exemple, int Message. Boîte (HWND h. Wnd, LPCTSTR lp. Texte, LPCTSTR lp. Légende, UINT u. Type) ; Cette fonction affiche une fenêtre avec un message et un bouton (ou des) boutons de sortie. Signification des paramètres : h. Wnd est un descripteur de la fenêtre dans laquelle la fenêtre de message apparaîtra, lp. Texte - texte qui apparaîtra dans la fenêtre, lp. Légende - texte dans le titre de la fenêtre, u. Type - type de fenêtre ; vous pouvez notamment déterminer le nombre de boutons de sortie.

Appel des fonctions de message de l'API Windows. Boîte (HWND h. Wnd, LPCTSTR lp. Texte, LPCTSTR lp. Légende, UINT u. Type) ; Presque tous les paramètres des fonctions API sont en réalité des entiers de 32 bits : HWND est un entier de 32 bits, LPCTSTR est un pointeur de 32 bits vers une chaîne, UINT est un entier de 32 bits. Le suffixe « A » est souvent ajouté au nom de la fonction pour passer à des versions plus récentes de la fonction.

Appel des fonctions de message de l'API Windows. Boîte (HWND h. Wnd, LPCTSTR lp. Texte, LPCTSTR lp. Légende, UINT u. Type) ; Lorsque vous utilisez MASM, vous devez ajouter @N N à la fin du nom - le nombre d'octets occupés par les arguments passés sur la pile. Pour les fonctions API Win 32, ce nombre peut être défini comme le nombre d'arguments n multiplié par 4 (octets dans chaque argument) : N=4*n. Pour appeler une fonction, utilisez l'instruction assembleur CALL. Dans ce cas, tous les arguments de la fonction lui sont transmis via la pile (commande PUSH). Sens de passage des arguments : DE GAUCHE À DROITE - DE BAS EN HAUT. L'argument u sera d'abord placé sur la pile. Taper. L'appel à la fonction spécifiée ressemblera à ceci : CALL Message. Boîte. A@16

Appel des fonctions de message de l'API Windows. Boîte (HWND h. Wnd, LPCTSTR lp. Texte, LPCTSTR lp. Légende, UINT u. Type) ; Le résultat de l'exécution d'une fonction API est généralement un entier renvoyé dans le registre EAX. La directive OFFSET représente un « décalage dans un segment » ou, traduit en termes de langage de haut niveau, un « pointeur » vers le début d'une ligne. La directive EQU, comme #define en SI, définit une constante. La directive EXTERNE indique au traducteur que la fonction ou l'identifiant est externe à ce module.

Exemple de programme « Bonjour à tous ! » . 686 P. MODÈLE PLAT, STDCALL. STACK 4096. DATA MB_OK EQU 0 STR 1 DB "Mon premier programme", 0 STR 2 DB "Bonjour tout le monde !", 0 HW DD ? Message EXTERNE. Boîte. A@16 : PROCHE. CODE DÉBUT : PUSH MB_OK PUSH OFFSET STR 1 PUSH OFFSET STR 2 PUSH HW CALL Message. Boîte. A@16 RET FIN DEBUT

La directive INVOKE Le traducteur de langage MASM permet également de simplifier les appels de fonctions à l'aide d'un outil macro - la directive INVOKE : fonction INVOKE, paramètre1, paramètre2, ... Il n'est pas nécessaire d'ajouter @16 à l'appel de fonction ; les paramètres sont écrits exactement dans l’ordre dans lequel ils sont donnés dans la description de la fonction. Grâce aux macros du traducteur, les paramètres sont placés sur la pile. Pour utiliser la directive INVOKE, vous devez disposer d'une description du prototype de fonction utilisant la directive PROTO sous la forme : Message. Boîte. A PROTO : DWORD, : DWORD Si un programme utilise de nombreuses fonctions API Win 32, il est conseillé d'utiliser la directive include C: masm 32includeuser 32. inc

Sujet 2.5 Bases de la programmation du processeur

À mesure que la durée du programme augmente, il devient de plus en plus difficile de mémoriser les codes des différentes opérations. Les mnémoniques fournissent une certaine aide à cet égard.

Le langage de codage de commandes symboliques est appelé assembleur.

Langage d'assemblage est un langage dans lequel chaque énoncé correspond exactement à une commande machine.

Assemblée appelé convertir un programme à partir du langage assembleur, c'est-à-dire préparer un programme en langage machine en remplaçant les noms symboliques des opérations par des codes machine et les adresses symboliques par des nombres absolus ou relatifs, ainsi qu'incorporer des programmes de bibliothèque et générer des séquences d'instructions symboliques en spécifiant des paramètres spécifiques en micro-équipes. Ce programme se trouve généralement dans la ROM ou est entré dans la RAM à partir de certains supports externes.

Le langage assembleur possède plusieurs fonctionnalités qui le distinguent des langages de haut niveau :

1. Il s'agit d'une correspondance biunivoque entre les instructions du langage assembleur et les instructions machine.

2. Un programmeur en langage assembleur a accès à tous les objets et instructions présents sur la machine cible.

Comprendre les bases de la programmation dans les langages orientés machine est utile pour :



Meilleure compréhension de l'architecture des PC et utilisation plus compétente des ordinateurs ;

Développer des structures plus rationnelles d'algorithmes pour les programmes de résolution de problèmes appliqués ;

La possibilité de visualiser et de corriger les programmes exécutables avec l'extension .exe et .com, compilés à partir de n'importe quel langage de haut niveau, en cas de perte des programmes sources (en appelant les programmes spécifiés dans le débogueur du programme DEBUG et en décompilant leur affichage en assembleur langue);

Compilation de programmes pour résoudre les problèmes les plus critiques (un programme écrit dans un langage orienté machine est généralement plus efficace - 30 à 60 % plus court et plus rapide des programmes obtenus grâce à la traduction à partir de langages de haut niveau)

Implémenter les procédures incluses dans le programme principal sous forme de fragments séparés dans le cas où elles ne peuvent être implémentées ni dans le langage de haut niveau utilisé, ni à l'aide des procédures de service du système d'exploitation.

Un programme en langage assembleur ne peut s'exécuter que sur une seule famille d'ordinateurs, tandis qu'un programme écrit dans un langage de haut niveau peut potentiellement s'exécuter sur différentes machines.

L’alphabet du langage assembleur est composé de caractères ASCII.

Les nombres ne sont que des entiers. Il y a:

Les nombres binaires se terminent par la lettre B ;

Nombres décimaux se terminant par la lettre D ;

Les nombres hexadécimaux se terminent par la lettre H.

RAM, registres, présentation des données

Pour une certaine série de MP, un langage de programmation individuel est utilisé - le langage assembleur.

Le langage assembleur occupe une position intermédiaire entre les codes machine et les langages de haut niveau. La programmation dans ce langage est plus facile. Un programme en langage assembleur utilise plus efficacement les capacités d'une machine spécifique (plus précisément, un MP) qu'un programme en langage de haut niveau (qui est plus simple pour un programmeur qu'un assembleur). Regardons les principes de base de la programmation dans les langages orientés machine en utilisant l'exemple du langage assembleur pour le MP KR580VM80. Une méthodologie générale est utilisée pour programmer dans le langage. Les techniques techniques spécifiques d'enregistrement des programmes sont associées aux caractéristiques de l'architecture et du système de commande du MP cible.

Modèle logiciel système à microprocesseur basé sur MP KR580VM80

Modèle logiciel du MPS selon la figure 1

Mémoire des ports MP

S Z A.C. P. C

Image 1

Du point de vue du programmeur, le MP KR580VM80 dispose des registres suivants accessibles par programme.

UN– Registre accumulateur 8 bits. C'est le registre principal du député. Toute opération effectuée dans une ALU consiste à placer l'un des opérandes à traiter dans l'accumulateur. Le résultat d’une opération dans l’ALU est également généralement stocké dans A.

B, C, D, E, H, L– Registres à usage général (GPR) 8 bits. Mémoire intérieure Député. Conçu pour stocker les informations traitées, ainsi que les résultats de l'opération. Lors du traitement de mots de 16 bits, les registres forment des paires BC, DE, HL et le double registre est appelé la première lettre - B, D, H. Dans une paire de registres, le plus élevé est le premier registre. Les registres H et L ont une propriété spéciale, utilisée à la fois pour stocker des données et pour stocker des adresses 16 bits de cellules RAM.

FL– registre de drapeaux (registre de signes) registre de 8 bits dans lequel sont stockés cinq signes du résultat des opérations arithmétiques et logiques effectuées dans le MP. Format FL conforme à l'image

Bit C (CY - carry) - report, mis à 1 s'il y a eu un report de l'ordre supérieur de l'octet lors de l'exécution d'opérations arithmétiques.

Bit P (parité) – parité, définie sur 1 si le nombre de un dans les bits du résultat est pair.

Le chiffre AC est un report supplémentaire, conçu pour stocker la valeur de report de la tétrade d'ordre inférieur du résultat.

Bit Z (zéro) – mis à 1 si le résultat de l’opération est 0.

Bit S (signe) – est mis à 1 si le résultat est négatif et à 0 si le résultat est positif.

PS– le pointeur de pile, un registre de 16 bits, conçu pour stocker l'adresse de la cellule mémoire où a été écrit le dernier octet inséré sur la pile.

RS– compteur de programme (program counter), un registre de 16 bits, destiné à stocker l'adresse de la prochaine instruction à exécuter. Le contenu du compteur de programme est automatiquement incrémenté de 1 immédiatement après la récupération de l'octet d'instruction suivant.

Dans la zone mémoire initiale d'adresse 0000Н – 07FF il y a programme de contrôle et des programmes de démonstration. C'est la zone ROM.

0800 – 0AFF - zone d'adresse pour l'enregistrement des programmes à l'étude. (RAM).

0В00 – 0ВВ0 - zone d'adresse pour l'écriture des données. (RAM).

0ВВ0 – adresse de départ de la pile. (RAM).

Une pile est une zone de RAM spécialement organisée destinée au stockage temporaire de données ou d'adresses. Le dernier numéro écrit dans la pile est affiché en premier. Le pointeur de pile stocke l'adresse de la dernière cellule de pile dans laquelle les informations sont écrites. Lorsqu'un sous-programme est appelé, l'adresse de retour vers le programme principal est automatiquement stockée sur la pile. En règle générale, au début de chaque sous-programme, le contenu de tous les registres impliqués dans son exécution est enregistré sur la pile et à la fin du sous-programme, il est restauré à partir de la pile.

Format de données et structure de commande du langage assembleur

La mémoire du MP KR580VM80 est un tableau de mots de 8 bits appelés octets. Chaque octet possède sa propre adresse de 16 bits, qui détermine sa position dans la séquence de cellules mémoire. Le MP peut adresser 65 536 octets de mémoire, qui peuvent être contenus à la fois dans la ROM et dans la RAM.

Format des données

Les données sont stockées en mémoire sous forme de mots de 8 bits :

D7 D6 D5 D4 D3 D2 D1 D0

Le bit de poids faible est le bit 0, le bit de poids fort est le bit 7.

Une commande est caractérisée par son format, c'est-à-dire le nombre de bits qui lui sont alloués, qui sont divisés octet par octet en certains champs fonctionnels.

Format de commande

Les commandes MP KR580VM80 ont un format à un, deux ou trois octets. Les commandes multioctets doivent être placées dans des langues adjacentes. Le format de la commande dépend des spécificités de l'opération en cours.

Le premier octet de la commande contient le code d'opération, écrit sous forme mnémonique.

Il détermine le format de commande et les actions qui doivent être effectuées par le MP sur les données lors de son exécution, ainsi que la méthode d'adressage, et peut également contenir des informations sur l'emplacement des données.

Les deuxième et troisième octets peuvent contenir des données sur lesquelles des opérations sont effectuées, ou des adresses indiquant l'emplacement des données. Les données sur lesquelles les actions sont effectuées sont appelées opérandes.

Format de commande à un octet selon la figure 2

Figure 4

Dans les commandes en langage assembleur, le code d'opération a une forme abrégée d'écriture de mots anglais - une notation mnémonique. Les mnémoniques (du grec mnémonique - l'art de la mémorisation) facilitent la mémorisation des commandes en fonction de leur objectif fonctionnel.

Avant exécution, le programme source est traduit à l'aide d'un programme de traduction appelé assembleur vers le langage des combinaisons de codes - langage machine, sous cette forme il est placé dans la mémoire du MP et est ensuite utilisé lors de l'exécution de la commande.


Méthodes d'adressage

Tous les codes d'opérande (entrée et sortie) doivent être situés quelque part. Ils peuvent être localisés dans les registres internes du député (le plus pratique et option rapide). Ils peuvent être localisés dans mémoire système(l'option la plus courante). Enfin, ils peuvent être localisés dans des périphériques d'E/S (cas le plus rare). L'emplacement des opérandes est déterminé par le code instruction. Exister différentes méthodes, avec lequel le code d'instruction peut déterminer où prendre l'opérande d'entrée et où placer l'opérande de sortie. Ces méthodes sont appelées méthodes d'adressage.

Pour le MP KR580VM80, les méthodes d'adressage suivantes existent :

Direct;

Registre;

Indirect;

Empilé.

Direct l'adressage suppose que l'opérande (d'entrée) est situé en mémoire immédiatement après le code d'instruction. L'opérande est généralement une constante qui doit être envoyée quelque part, ajoutée à quelque chose, etc. les données sont contenues dans le deuxième ou le deuxième et le troisième octet de la commande, l'octet de données faible étant situé dans le deuxième octet de la commande, et l'octet de poids fort dans le troisième octet de commande.

Droit L'adressage (ou absolu) suppose que l'opérande (entrée ou sortie) se trouve en mémoire à l'adresse dont le code se trouve à l'intérieur du programme immédiatement après le code d'instruction. Utilisé dans les commandes à trois octets.

Registre l'adressage suppose que l'opérande (entrée ou sortie) se trouve dans le registre interne du MP. Utilisé dans les commandes à un octet

Indirect L'adressage (implicite) suppose que le registre interne du MP ne contient pas l'opérande lui-même, mais son adresse en mémoire.

Empiler l'adressage suppose que la commande ne contient pas d'adresse. Adressage des cellules mémoire à l'aide du contenu du registre SP 16 bits (pointeur de pile).

Système de commande

Le système de commandement MP est une liste complète des actions élémentaires que le MP est capable d'effectuer. Le MP contrôlé par ces commandes effectue des actions simples, telles que des opérations arithmétiques et logiques élémentaires, le transfert de données, la comparaison de deux valeurs, etc. Le nombre de commandes du MP KR580VM80 est de 78 (en tenant compte des modifications 244).

On distingue les groupes de commandes suivants :

Transmission de données;

Arithmétique;

Casse-tête;

Commandes de saut ;

Commandes d'entrée/sortie, de contrôle et de pile.


Symboles et abréviations utilisés pour décrire les commandes et composer des programmes

Symbole Réduction
ADDR Adresse 16 bits
DONNÉES données 8 bits
DONNÉES 16 données 16 bits
PORT Adresse du périphérique d'E/S 8 bits
OCTET 2 Deuxième octet de la commande
OCTET 3 Troisième octet de commande
R, R1, R2 Un des registres : A, B, C, D, E, H, L
R.P. L'une des paires de registres : B - spécifie la paire BC ; D - spécifie une paire DE ; H – spécifie la paire HL
RH Premier registre du couple
R.L. Deuxième registre du couple
Λ Multiplication logique
V Ajout logique
Ajout modulo deux
M Une cellule mémoire dont l'adresse spécifie le contenu de la paire de registres HL, c'est-à-dire M = (HL)



Haut