Composants de langage d'assemblage de base et structure de commande. Format des données et structure des instructions du langage d'assemblage. Sujet "Programmation système"

Introduction.

Le langage dans lequel le programme original est écrit est appelé saisir langue, et la langue dans laquelle il est traduit pour exécution par le processeur - fin de semaine langue. Le processus de conversion d'une langue d'entrée en une 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 traductions : compilation et interprétation.

À compilation le programme source est d'abord complètement traduit en un programme équivalent dans la langue cible, appelé objet programme puis exécuté. Ce processus est effectué à l'aide d'un programmes, appelé compilateur. Un compilateur pour lequel le langage d'entrée est une représentation symbolique 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 repose sur 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 au préalable toutes commande 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 d'assemblage décrit ci-dessous est implémenté à l'aide de la compilation.

Caractéristiques de la langue.

Les principales caractéristiques de l'assembleur :

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

) mnémonique est utilisé

Soustractions (

multiplier (

Divisions (

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

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

● la langue donne accès à tous les objets et équipes. Les langages de haut niveau n'ont pas cette capacité. Par exemple, le langage d'assemblage vous permet de vérifier un bit de registre d'indicateur et un langage de haut niveau (par exemple,

) n'a pas cette capacité. Notez 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 d'assemblage, mais ils ont la syntaxe d'un langage de haut niveau ;

● langage d'assemblage 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, écrire et déboguer un programme en langage assembleur prend beaucoup de temps. Malgré cela, le langage d'assemblage est devenu large utilisation en raison des circonstances suivantes :

● Un programme écrit en langage assembleur est beaucoup plus petit et beaucoup plus rapide qu'un programme écrit dans un langage de haut niveau. Pour certaines applications, ces indicateurs jouent un rôle primordial, par exemple, de nombreux programmes système (y compris des compilateurs), des programmes de 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 n'est généralement pas possible 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 embarqués en temps réel.

Dans la plupart des programmes, seul un petit pourcentage du code total est responsable d'un grand pourcentage 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, l'assembleur et l'un des langages de haut niveau sont utilisés.

Format d'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 allouée au champ de libellé. Un libellé est un nom symbolique, ou identifiant, adresses mémoire. Il est nécessaire pour pouvoir :

● faire une transition conditionnelle ou inconditionnelle vers la commande ;

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

Ces déclarations sont étiquetées. Pour désigner un nom, on utilise des lettres (majuscules) de l'alphabet anglais et des chiffres. Le nom doit commencer par une lettre et se terminer par deux-points. L'étiquette deux-points peut être écrite sur une ligne séparée, et l'opcode peut être écrit sur la ligne suivante dans la colonne 2, ce qui simplifie le travail du compilateur. L'absence de deux-points rend impossible la distinction entre une étiquette et un opcode s'ils sont sur des lignes séparées.

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

Le champ label ne doit pas contenir les mêmes noms, puisque le label est associé aux adresses des commandes. Si pendant l'exécution du programme, il n'est pas nécessaire d'appeler une commande ou des données de la mémoire, le champ d'étiquette reste vide.

Champ de code de transaction.

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

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

), et de stocker le contenu du registre en mémoire - le mnémonique

). Dans les langages d'assemblage

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

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

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

Champ opérande.

Ici se trouve Informations Complémentaires nécessaire pour effectuer l'opération. Dans le champ des opérandes pour les instructions de saut, l'adresse où vous voulez sauter est indiquée, ainsi que les adresses et les registres qui sont des opérandes pour l'instruction machine. A titre d'exemple, voici les opérandes utilisables pour les processeurs 8 bits

● données numériques,

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

En conséquence, les systèmes de numération binaire, octal, hexadécimal, décimal (

peut ne pas être enregistré). Si le premier chiffre du nombre hexadécimal est A, B, C,

Ensuite, un 0 (zéro) non significatif 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 de numérotation (par exemple, 10V - adresse de registre

en système binaire);

● identifiants,

pour les paires d'avions immatriculés,

Les premières lettres B

H; pour une paire d'accumulateur et de registre de fonctions -

; pour le compteur de programme -

; pour le pointeur de pile -

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

(lorsque 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 avec l'identifiant M1 ;

● expression,

qui sont construits en reliant les données décrites ci-dessus à l'aide d'opérateurs arithmétiques et logiques. Notez que la manière dont l'espace de données est réservé dépend de la version du langage. Développeurs de langage d'assemblage pour

Définir le mot), et introduit plus tard Option alternative.

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

En version linguistique

utilisé

définir une constante).

Les processeurs traitent des opérandes de longueurs différentes. 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 32 bits (type

); AX - pour 16 bits (type

et AN - pour 8 bits (type

● pour les processeurs

des suffixes sont ajoutés à chaque opcode : suffix

Pour le genre

; suffixe ".B" pour le type

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

) et les mots dans le registre 64 bits utilisent des 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 à une personne. Ils peuvent être nécessaires pour modifier un programme qui, sans ces commentaires, peut être complètement incompréhensible même pour les programmeurs expérimentés. Un commentaire commence par un caractère et est utilisé pour expliquer et documenter les programmes. Le caractère de début d'un commentaire peut être :

● point-virgule (;) dans les langues pour les sous-traitants de l'entreprise

Point d'exclamation(!) dans les langues pour

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

Pseudo commandes (directives).

En langage assembleur, on distingue deux grands types de commandes :

basique instructions équivalentes au code machine du processeur. Ces commandes effectuent tout le traitement fourni par le programme ;

pseudo-commandes ou directives, conçu pour servir le processus de traduction du programme dans le langage des combinaisons de codes. A titre d'exemple, dans le tableau. 5.2.2 montre quelques pseudo-commandes de l'as-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 :

● écrire la séquence de commandes souhaitée chaque fois qu'elle se produit. 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. Une telle sortie a ses inconvénients : il faut à chaque fois exécuter une instruction d'appel de procédure spéciale et une instruction de retour, ce qui, avec une séquence courte et fréquemment utilisée, peut fortement réduire 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 considéré comme une pseudo-commande destinée à retraduire un groupe de commandes fréquemment rencontrées dans un programme.

Une macro, ou instruction de macro, est caractérisée par trois aspects : la définition de macro, l'inversion de macro et l'expansion de macro.

macro définition

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

Une macro a la structure suivante :

Liste d'expressions ; macro définition

La structure de définition de macro ci-dessus comporte trois parties :

● en-tête

macro contenant le nom

Pseudo-commande

et un ensemble de paramètres ;

● pointillé corps macro ;

● équipe

l'obtention du diplôme

macro définitions.

Un jeu de paramètres de macro contient une liste de tous les paramètres indiqués dans le champ d'opérande pour le groupe d'instructions sélectionné. Si ces paramètres sont donnés plus tôt dans le programme, ils peuvent être omis dans l'en-tête de définition de macro.

Pour le réassemblage du groupe d'instructions sélectionné, un appel est utilisé, composé du nom

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

Lorsque l'assembleur rencontre une définition de macro lors de la compilation, il la stocke dans la table de définition de macro. Avec des 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 s'appelle macro-inversion(appel de macro), et son remplacement par le corps de la macro - extension macro.

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

L'expansion de la macro se produit pendant le processus d'assemblage, pas pendant l'exécution du programme. Les manières de manipuler les chaînes de caractères sont attribuées à outils macros.

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

● Lors de la première passe, toutes les définitions de macros sont conservées et les appels de macros sont développés. Dans ce cas, le programme source 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 un corps de macro ;

● La deuxième passe traite le programme reçu sans macros.

Macros avec paramètres.

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

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

● avec officiel paramètres. Lors du développement de la macro, chaque paramètre formel qui apparaît 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 montre deux séquences de commandes similaires, différant en ce que la première permute P et

Et le deuxième

Le programme 2 comprend une macro avec deux paramètres formels P1 et P2. Lors de l'expansion de la macro, chaque caractère P1 à l'intérieur du 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 un appel de macro

le programme 2 est marqué : P,

Le premier paramètre réel,

Le deuxième paramètre réel.

Programme 1

Programme 2

MOV EBX,Q MOV EAX,Pl

MOV Q,EAX MOV EBX,P2

MOV P,EBX MOV P2,EAX

Capacités étendues.

Considérez quelques fonctionnalités avancées du langage

Si une macro contenant une instruction de branchement conditionnel et une étiquette vers laquelle sauter est appelée deux fois ou plus, l'étiquette sera dupliquée (problème de duplication d'étiquette), ce qui provoquera une erreur. Par conséquent, chaque appel se voit attribuer (par le programmeur) une étiquette distincte en tant que paramètre. En langue

le label est déclaré local (

) et grâce aux fonctionnalités avancées, l'assembleur génère automatiquement une étiquette différente à chaque expansion de la macro.

vous permet de définir des macros à l'intérieur d'autres macros. Cette fonction avancée est très utile lorsqu'elle est associée à une liaison conditionnelle de programmes. Considérer

SI WORDSIZE GT 16 M2 MACRO

La macro M2 peut être définie dans les deux parties de la déclaration

Cependant, la définition varie selon que le programme est assemblé sur un processeur 16 bits ou 32 bits. Si M1 n'est pas appelée, 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, afin d'éviter une boucle infinie, la macro doit se passer un paramètre, qui change à chaque expansion, et aussi vérifier ce paramètre et termine la récursivité lorsque le paramètre atteint une certaine valeur.

Sur l'utilisation des macros en assembleur.

Lors de l'utilisation de macros, l'assembleur doit être capable d'effectuer deux fonctions : enregistrer les définitions de macro Et développer les appels de macro.

Enregistrement des définitions de macro.

Tous les noms de macro sont stockés dans une table. Chaque nom est accompagné d'un pointeur sur 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 commune dans laquelle, avec les noms de macros, il y a toutes les commandes et directives de la machine.

Lorsque vous rencontrez une macro lors de l'assemblage 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ù le corps de la macro sera stocké ;

● 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é comme caractère de paramètre formel.

Extension d'appel 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 suspend temporairement la lecture des données d'entrée à partir du périphérique d'entrée et commence à lire le corps de la macro enregistrée. Les paramètres formels extraits du corps de la macro sont remplacés par les paramètres réels et fournis par l'appel. Une esperluette & devant les paramètres permet à l'assembleur de les reconnaître.

Bien qu'il existe de nombreuses versions d'assembleur, les processus d'assemblage ont des caractéristiques communes et sont similaires à bien des égards. Le travail d'un assembleur à deux passes est considéré ci-dessous.

Assembleur en deux passes.

Le programme se compose d'un certain nombre d'opérateurs. Par conséquent, il semblerait que la séquence d'actions suivante puisse être utilisée lors de l'assemblage :

● le traduire en langage machine ;

● transférer le code machine reçu dans un fichier et la partie correspondante de la liste - dans un autre fichier ;

● répéter les procédures ci-dessus jusqu'à ce que l'intégralité du programme soit diffusée.

Cependant, cette approche n'est pas efficace. Un exemple est le soi-disant problème lien principal. Si la première instruction est un saut à l'instruction P à la toute fin du programme, l'assembleur ne peut pas la traduire. Il doit d'abord déterminer l'adresse de l'opérateur P, et pour cela il est nécessaire de lire tout le programme. Chaque lecture complète du programme original est appelée passage. Montrons comment nous pouvons résoudre le problème de référence directe en utilisant deux passes :

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

● au premier passage, convertir programme dans un formulaire intermédiaire et enregistrez-le dans un tableau, et la deuxième passe est effectuée non pas selon le programme d'origine, mais selon le tableau. Cette méthode d'assemblage permet de gagner du temps, car aucune opération d'E/S n'est effectuée lors de la deuxième passe.

Premier passage.

But du premier passage- construire une table de symboles. Comme indiqué ci-dessus, un autre objectif de la première passe est d'enregistrer toutes les définitions de macro et de développer les appels au fur et à mesure qu'ils apparaissent. Par conséquent, la définition des caractères et l'expansion des macros se produisent dans la même passe. Le symbole peut être soit étiqueter, ou signification, qui reçoit un nom spécifique à l'aide de la directive -you :

;Valeur - taille de la mémoire tampon

En donnant une signification aux noms symboliques dans le champ d'étiquette d'instruction, l'assembleur définit essentiellement les adresses que chaque instruction aura lors de l'exécution du programme. Pour ce faire, l'assembleur lors du processus d'assemblage enregistre compteur d'adresses d'instructions(

) comme variable spéciale. Au début de la première passe, la valeur de la variable spéciale est définie sur 0 et incrémenté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 du programme indiquant la longueur des commandes et les valeurs des compteurs. Les tableaux sont générés lors de la première passe noms de symboles, directives Et codes de fonctionnement, et si nécessaire littéral tableau. Un littéral est une constante pour laquelle l'assembleur réserve automatiquement de la mémoire. On remarque tout de suite que les processeurs modernes contiennent des instructions avec des adresses directes, donc leurs assembleurs ne supportent pas les littéraux.

Tableau des symboles

contient un élément pour chaque nom (tableau 5.2.4). Chaque élément de la table des symboles 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 remappage 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 des directives.

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

Tableau des codes d'opération.

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

Deuxième passe.

But de la deuxième passe- créer un programme objet et imprimer, si nécessaire, un protocole d'assemblage ; les informations de sortie nécessaires à l'éditeur de liens pour lier des procédures qui ont été assemblées à différents moments dans un fichier exécutable.

Dans la deuxième passe (comme dans la première), les lignes contenant les instructions sont lues et traitées les unes après les autres. L'opérateur d'origine et la sortie qui en est dérivée en hexadécimal objet le code peut être imprimé ou mis en mémoire tampon pour une impression ultérieure. Après avoir réinitialisé le compteur d'adresse de commande, la commande est appelée déclaration suivante.

Le programme d'origine peut contenir des erreurs, par exemple :

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

● L'opcode est représenté par un nom invalide (en raison d'une faute de frappe), n'est pas fourni avec suffisamment d'opérandes ou contient trop d'opérandes ;

● pas d'opérateur

Certains assembleurs peuvent détecter un symbole indéfini et le remplacer. Cependant, dans la plupart des cas, lorsqu'une instruction contenant une erreur est trouvée, 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 DU NOM DE MIRZO ULUGBEK

FACULTÉ DES TECHNOLOGIES INFORMATIQUES

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

Complété:

Tachkent 2003.

Préface.

Langage d'assemblage et structure d'instructions.

Structure du fichier EXE (analyse sémantique).

Structure d'un fichier COM.

Comment le virus fonctionne et se propage.

Désassembleur.

Programmes.

Avant-propos

Le métier de programmeur est incroyable et unique. À notre époque, la science et la vie ne peuvent être imaginées sans les dernières technologies. Tout ce qui est lié à l'activité humaine ne peut se passer l'informatique. Et cela contribue à son développement élevé et à sa perfection. Même si le développement des ordinateurs personnels a commencé il n'y a pas si longtemps, mais pendant ce temps, des étapes colossales ont été franchies dans les produits logiciels et pendant longtemps ces produits seront largement utilisés. Le domaine des connaissances liées à l'informatique a explosé, tout comme la technologie qui s'y rapporte. Si nous ne prenons pas en considération le côté commercial, alors nous pouvons dire qu'il n'y a pas d'étrangers dans ce domaine d'activité professionnelle. Beaucoup sont engagés dans le développement de programmes sans but lucratif ou lucratif, mais de leur plein gré, par passion. Bien sûr, cela ne devrait pas affecter la qualité du programme, et dans ce secteur, pour ainsi dire, il existe une concurrence et une demande de performances de qualité, de travail stable et répondant à toutes les exigences de notre époque. 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. Certaines variétés de microprocesseurs sont très différentes les unes des autres. Ces microprocesseurs diffèrent les uns des autres en termes de capacité en bits et de 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 refonte des attitudes envers le langage d'assemblage pour deux raisons principales. Premièrement, les programmes écrits en langage d'assemblage nécessitent beaucoup moins de mémoire et d'exécution. Deuxièmement, la connaissance du langage d'assemblage et du code machine qui en résulte donne une compréhension de l'architecture de la machine, ce qui n'est guère fourni lorsque l'on travaille dans un langage de haut niveau. Bien que la plupart des ingénieurs logiciels développent dans des langages de haut niveau tels que Pascal, C ou Delphi, qui est plus facile à écrire des programmes, le plus puissant et le plus efficace logiciel entièrement ou partiellement écrit en langage assembleur. Les langages de haut niveau ont été conçus pour éviter des caractéristiques techniques ordinateurs spécifiques. Et le langage d'assemblage, à 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 particulier, il faut connaître son architecture. De nos jours, la vue de la principale produit logiciel est un fichier EXE. Considérant côtés positifs ceci, l'auteur du programme peut être sûr de son inviolabilité. Mais souvent c'est loin d'être le cas. Il y a aussi un désassembleur. À l'aide d'un désassembleur, vous pouvez trouver les interruptions et les codes de programme. Il ne sera pas difficile pour une personne qui maîtrise bien l'assembleur de refaire tout le programme à son goût. C'est peut-être de là que vient 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 néanmoins il y a encore des gens qui s'intéressent à cette tâche non pas dans l'optique de causer du tort, mais par intérêt pour la programmation système. Ecrire des virus sur des raisons différentes. Certains aiment les appels système, d'autres perfectionnent leurs connaissances en assembleur. Je vais essayer d'expliquer tout cela dans mon dissertation. Il indique également non seulement la structure du fichier EXE, mais également le langage d'assemblage.

^ Langage d'assemblage.

Il est intéressant de suivre, depuis l'apparition des premiers ordinateurs jusqu'à nos jours, la transformation des idées sur le langage d'assemblage chez les programmeurs.

Il était une fois, l'assembleur était un langage sans savoir lequel il était impossible de faire faire quoi que ce soit d'utile à un ordinateur. Peu à peu, la situation a changé. Des moyens de communication plus pratiques avec un ordinateur sont apparus. Mais, contrairement à d'autres langages, l'assembleur n'est pas mort, de plus, il ne pouvait pas le faire en principe. Pourquoi? A la recherche d'une réponse, nous allons essayer de comprendre ce qu'est le langage d'assemblage en général.

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

Il est impossible de résoudre réellement des problèmes liés au matériel (ou même, d'ailleurs, des problèmes liés au matériel, comme l'amélioration de la vitesse d'un programme), sans connaissances en assembleur.

Un programmeur ou tout autre utilisateur peut utiliser n'importe quel outil de haut niveau, jusqu'aux programmes de construction de mondes virtuels, et peut-être même ne pas soupçonner que l'ordinateur exécute réellement non 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 ternes de commandes 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 se soit mal passé. Par exemple, son programme doit fonctionner avec un appareil inhabituel ou effectuer d'autres actions nécessitant une connaissance des principes du matériel informatique. Peu importe à quel point un programmeur est intelligent, peu importe la qualité du langage dans lequel il a écrit son merveilleux programme, il ne peut pas 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 en assembleur ou prennent en charge l'accès au niveau de programmation assembleur.

Bien sûr, le temps des wagons informatiques est déjà révolu. Comme le dit le dicton, vous ne pouvez pas embrasser l'immensité. Mais il y a quelque chose en commun, une sorte de fondation sur laquelle repose toute formation sérieuse en informatique. Il s'agit de connaissances sur les principes de fonctionnement de l'ordinateur, son architecture et son langage d'assemblage en tant que reflet et incarnation de ces connaissances.

Un ordinateur moderne type (i486 ou Pentium) comprend les composants suivants (Figure 1).

Riz. 1. Ordinateur et périphériques

Riz. 2. Schéma fonctionnel d'un 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. Logiquement, il est clair qu'il joue le rôle d'un dispositif de coordination. Jetons un coup d'oeil à l'intérieur bloc système(pas besoin d'essayer de pénétrer à l'intérieur du moniteur - il n'y a rien d'intéressant là-bas, en plus c'est dangereux): nous ouvrons le boîtier et voyons des cartes, des blocs, des 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.

Examinons le schéma de la Fig. 2 dans un style peu conventionnel.
C'est dans la nature humaine de rencontrer quelque chose de nouveau, de chercher des associations qui peuvent l'aider à connaître l'inconnu. Quelles associations l'ordinateur évoque-t-il ? Pour moi, par exemple, l'ordinateur est souvent associé à la personne elle-même. Pourquoi?

Une personne créant un ordinateur quelque part au plus profond de lui-même pensait créer quelque chose de semblable à lui-même. L'ordinateur a des organes de perception des informations du monde extérieur - il s'agit d'un clavier, d'une souris, de lecteurs de disques magnétiques. Sur la fig. 2 ces organes sont situés à droite des bus système. L'ordinateur a des organes qui "digèrent" les informations reçues - ce sont CPU et la mémoire de travail. Et, enfin, l'ordinateur a des organes de la parole qui donnent les résultats du traitement. Ce sont aussi quelques-uns des appareils sur la droite.

Ordinateurs modernes, bien sûr, loin d'être humain. Ils peuvent être comparés à des êtres interagissant 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 d'instructions machine. Quel que soit le niveau de communication avec un ordinateur, tout se résume en fin de compte à une séquence ennuyeuse et monotone d'instructions machine.
Chaque commande de la machine est une sorte de stimulus pour l'excitation de tel ou tel réflexe inconditionné. La réaction à ce stimulus est toujours sans ambiguïté et est « câblée » dans le bloc de microcommandes sous la forme d'un microprogramme. Ce microprogramme met en oeuvre des actions pour la mise en oeuvre d'une commande machine, mais déjà au niveau des signaux donnés à certains logique ordinateur, contrôlant ainsi les différents sous-systèmes de l'ordinateur. C'est ce qu'on appelle le principe du contrôle des microprogrammes.

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 plat sur lequel la nourriture (programmes) est livrée selon certaines règles gastriques (ordinateur). Seul l'estomac d'un ordinateur aime les aliments diététiques et monotones - donnez-lui des informations structurées, sous la forme de séquences strictement organisées de zéros et de uns, dont les combinaisons constituent le langage machine.

Ainsi, étant extérieurement polyglotte, l'ordinateur ne comprend qu'un seul langage - le langage des instructions de la machine. Bien sûr, pour communiquer et travailler avec un ordinateur, il n'est pas nécessaire de connaître ce langage, mais presque tout programmeur professionnel est tôt ou tard confronté à la nécessité de l'apprendre. Heureusement, le programmeur n'a pas besoin d'essayer de comprendre la signification de diverses combinaisons de nombres binaires, car dès les années 50, les programmeurs ont commencé à utiliser l'analogue symbolique du langage machine pour la programmation, appelé langage d'assemblage. Ce langage reflète fidèlement toutes les caractéristiques du langage machine. C'est pourquoi, contrairement aux langages de haut niveau, le langage d'assemblage est différent pour chaque type d'ordinateur.

De ce qui précède, on peut conclure que, le langage d'assemblage de l'ordinateur étant "natif", le programme le plus efficace ne peut être écrit que dans celui-ci (à condition qu'il soit écrit par un programmeur qualifié). Il y a un petit "mais" ici : c'est un processus très laborieux qui demande beaucoup d'attention et d'expérience pratique. Par conséquent, en réalité, l'assembleur écrit principalement des programmes qui devraient fournir travail efficace avec du matériel. Parfois, des parties critiques du programme en termes de temps d'exécution ou de consommation de mémoire sont écrites en assembleur. Par la suite, ils sont réalisé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 d'assemblage de n'importe quel ordinateur uniquement après avoir découvert quelle partie de l'ordinateur est laissée visible et disponible pour la programmation dans ce langage. C'est ce qu'on appelle le modèle de programme informatique, dont une partie est le modèle de programme du microprocesseur, qui contient 32 registres qui sont plus ou moins disponibles pour être utilisés par le programmeur.

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

^ 16 registres personnalisés ;

16 registres système.

Les programmes en langage d'assemblage utilisent très fortement les registres. La plupart des registres ont un objectif fonctionnel spécifique.

Comme leur nom l'indique, les registres d'utilisateurs sont appelés 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 (RON)) :

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

registres d'état et de contrôle :

Les drapeaux enregistrent les eflags/drapeaux ;

registre de pointeur de commande eip/ip.

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

Pourquoi beaucoup de ces registres sont-ils affichés avec une barre oblique ? Non, ce ne sont pas des registres différents - ils font partie d'un grand registre 32 bits. Ils peuvent être utilisés dans le programme en tant qu'objets séparés. Cela a été fait pour garantir l'opérabilité des programmes écrits pour les modèles de microprocesseurs 16 bits plus récents d'Intel, à commencer par le i8086. Les microprocesseurs i486 et Pentium ont 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. Ceci est fait, comme nous l'avons noté ci-dessus, pour la compatibilité avec les modèles de microprocesseurs 16 bits plus récents d'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 de l'unité arithmétique et logique (ALU), ils sont également appelés registres ALU :

eax/ax/ah/al (registre d'accumulateur) - accumulateur.
Utilisé pour stocker des données intermédiaires. Dans certaines commandes, l'utilisation de ce registre est obligatoire ;

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.
Il est utilisé dans les commandes 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 d'organisation de boucle, en plus de transférer le contrôle à une commande située à une certaine adresse, analyse et décrémente 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 des données intermédiaires. Certaines commandes nécessitent son utilisation ; 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, chacune pouvant avoir une longueur de 32, 16 ou 8 bits :

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

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

Dans l'architecture du microprocesseur au niveau matériel et logiciel, une structure de données telle qu'une pile est supportée. Pour travailler avec la pile dans le système d'instructions du microprocesseur, il existe des commandes spéciales, 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 (registre de pointeur de base) - registre de pointeur de base de cadre de pile.
Conçu pour organiser un accès aléatoire aux données à l'intérieur de la pile.

Une pile est une zone de programme pour le stockage temporaire de données arbitraires. Bien entendu, des données peuvent également être stockées dans le 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 est que sa zone est réutilisée, et le stockage des données sur la pile et leur extraction à partir de là se font à l'aide de commandes push et pop efficaces sans spécifier de noms.
La pile est traditionnellement utilisée, par exemple, pour stocker le contenu des registres utilisés par le programme avant d'appeler un sous-programme, qui, à son tour, utilisera les registres du processeur "pour ses propres besoins". Le contenu d'origine des registres s'échappe de la pile lors du 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 prendre à partir de là et les utiliser dans son exécution. Particularité pile est une sorte d'ordre d'échantillonnage des données qu'elle contient : à tout moment, seul l'élément supérieur est disponible sur la pile, c'est-à-dire le dernier élément chargé sur la pile. Faire sauter 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 de mémoire allouée à la pile, en partant du bas de la pile (c'est-à-dire depuis son adresse maximale) jusqu'aux adresses successivement décroissantes. L'adresse de l'élément accessible par le haut est stockée dans le registre de pointeur de pile SP. Comme toute autre zone de la mémoire programme, la pile doit être incluse dans un segment ou former un segment séparé. Dans les deux cas, l'adresse de segment de ce segment est placée dans le registre de pile de segments SS. Ainsi, une paire de registres SS:SP décrit l'adresse d'une cellule de pile disponible : 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). Faisons attention au fait 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 chargement d'un élément (dans cet exemple, le contenu du registre AX), c - après chargement du deuxième élément (contenu du registre DS), d - après déchargement d'un élément, e - après avoir déchargé deux éléments et revenir à l'état d'origine.

Le chargement sur la pile est effectué par une commande spéciale push stack. 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 enregistrer temporairement le contenu du registre AX sur la pile, nous devons exécuter la commande

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

déplacera la pile dans l'état illustré à la Fig. 1.10, ch. La pile contiendra désormais deux éléments, seul celui du haut étant accessible, pointé par le pointeur de pile SP. Si, après un certain temps, nous avons besoin de restaurer le contenu original des registres sauvegardés sur la pile, nous devons exécuter les commandes pop (pop) de la pile :

pop-DS
HACHE pop

Quelle doit être la taille de la pile ? Cela dépend de l'intensité de son utilisation 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, en particulier 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 DOS y pousse le contenu des registres et d'autres informations relatives au programme interrompu. Par conséquent, même si le programme n'utilise pas du tout la pile, celle-ci doit toujours être présente dans le programme et avoir une taille d'au moins plusieurs dizaines de mots. Dans notre premier exemple, nous mettons 128 mots sur la pile, ce qui est largement suffisant.

^ Structure du programme d'assemblage

Un programme en langage assembleur est un ensemble de blocs de mémoire appelés segments de mémoire. Un programme peut consister en un ou plusieurs de ces blocs-segments. Chaque segment contient une collection de phrases de langage, dont chacune occupe une ligne distincte de code de programme.

Les instructions d'assemblage sont de quatre types :

commandes ou instructions qui sont les équivalents symboliques des instructions machine. Pendant le processus de traduction, les instructions d'assemblage sont converties en commandes correspondantes du jeu d'instructions du microprocesseur ;

macro-commandes - phrases du texte du programme conçues d'une certaine manière et remplacées par d'autres phrases lors de la traduction;

directives qui indiquent au compilateur assembleur d'effectuer une action. Les directives n'ont pas d'équivalent dans la représentation machine ;

lignes de commentaire contenant n'importe quel caractère, y compris les lettres de l'alphabet russe. Les commentaires sont ignorés par le traducteur.

^ Syntaxe du langage 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 façons les plus courantes de décrire un langage de programmation de cette manière sont les diagrammes de syntaxe et les formes Backus-Naur étendues. Pour utilisation pratique les diagrammes de syntaxe sont plus pratiques. Par exemple, la syntaxe des instructions en langage assembleur peut être décrite à l'aide des diagrammes de syntaxe illustrés dans les figures suivantes.

Riz. 5. Format de phrase en assembleur

Riz. 6. Directives de format

Riz. 7. Format des commandes et des macros

Sur ces dessins :

nom d'étiquette - un identifiant dont la valeur est l'adresse du premier octet de la phrase de 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 certaine directive, certaines caractéristiques peuvent être affectées à ce nom ;

le code d'opération (COP) et la directive sont des désignations mnémoniques de l'instruction machine, de la macro-instruction ou de la directive de traduction correspondantes ;

opérandes - parties de la commande, de la macro ou des directives de l'assembleur, désignant les objets sur lesquels les opérations sont effectuées. Les opérandes assembleur sont décrits par des expressions avec des constantes numériques et textuelles, des étiquettes de variables et des identificateurs utilisant des signes d'opération et des mots réservés.

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

Les caractères autorisés lors de l'écriture du texte des programmes sont :

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

Chiffres de 0 à 9 ;

Signes ?, @, $, _, & ;

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

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

Les jetons sont :

les identificateurs sont des séquences de caractères valides utilisés pour désigner des objets de programme tels que des opcodes, des noms de variables et des noms d'étiquettes. La règle d'écriture des identifiants est la suivante : un identifiant peut être composé d'un ou plusieurs caractères. En tant que caractères, 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 chiffre. La longueur de l'identifiant peut aller jusqu'à 255 caractères, bien que le traducteur n'accepte que les 32 premiers caractères 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 dire 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 du langage d'assemblage.

Les commandes d'assemblage ouvrent la possibilité de transférer leurs exigences à l'ordinateur, le mécanisme de transfert de contrôle dans le programme (boucles et sauts) pour les comparaisons logiques et l'organisation du programme. Cependant, les tâches de programmation sont rarement aussi simples. La plupart des programmes contiennent une série de boucles dans lesquelles plusieurs instructions sont répétées jusqu'à ce qu'une certaine exigence soit atteinte, et diverses vérifications pour déterminer laquelle des plusieurs actions à effectuer. Certaines commandes 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 de commande. Comme mentionné précédemment, il existe différentes commandes pour différents processeurs, mais nous considérerons 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 du tableau qui reflète la structure du registre des drapeaux eflags :

La ligne du bas de ce tableau répertorie les valeurs des drapeaux après l'exécution de la commande. Dans ce cas, les notations suivantes sont utilisées :

1 - après l'exécution de la commande, 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 ;

Après l'exécution de la commande, le drapeau est indéfini ;

espace - après l'exécution de la commande, le drapeau ne change pas ;

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

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

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

i8, i16, i32 - opérande immédiat de taille octet, mot ou double mot ;

a8, a16, a32 - adresse relative (décalage) dans le segment de code.

Commandes (par ordre alphabétique) :

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

AJOUTER
(Ajout)

Ajout

^ Aperçu de la commande :

ajouter destination, source

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

Algorithme de travail :

ajouter les opérandes source et destination ;

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

définir des drapeaux.

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

Application:
La commande add est utilisée pour additionner 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 bornes de l'opérande destination (un débordement se produit), alors cette situation doit être prise en compte en analysant le flag cf puis éventuellement en utilisant la commande adc. Par exemple, ajoutons les valeurs dans le registre ax et la zone mémoire ch. Lors de l'ajout, vous devez tenir compte de la possibilité de débordement.

Registre plus registre ou mémoire :

|000000dw|modregr/rm|

Registre AX (AL) plus valeur immédiate :

|0000010w|--données--|données si w=1|

Registre ou mémoire plus valeur immédiate :

|100000sw|mod000r/m|--données--|données si BW=01|

APPEL
(APPEL)

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

^ Aperçu de la commande :

But:

transfert de contrôle à une procédure close ou far avec mémorisation de l'adresse du point de retour sur la pile ;

le changement de tâche.

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

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

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

R16, 32 ou m16, 32 - définissent un registre ou une cellule de mémoire contenant des décalages dans le segment d'instruction en cours, où 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 drapeaux sont modifiées en fonction des informations sur le registre eflags dans le segment d'état TSS de la tâche vers laquelle basculer.
Application:
La commande d'appel permet d'organiser un transfert de contrôle flexible et multivarié vers un sous-programme tout en conservant 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|décalage-bas|décalage-haut|seg-bas|seg-haut|

CMP
(comparer les opérandes)

Comparaison d'opérandes

^ Aperçu de la commande :

cmp opérande1, opérande2

Objet : comparaison de deux opérandes.

Algorithme de travail :

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

en fonction du résultat, définissez des drapeaux, ne modifiez pas l'opérande1 et l'opérande2 (c'est-à-dire, ne stockez pas le résultat).

Application:
Cette commande utilisé pour comparer deux opérandes par soustraction, alors que les opérandes ne changent pas. Les drapeaux sont définis à la suite de l'exécution de la commande. L'instruction cmp est utilisée avec les instructions de saut conditionnel et l'instruction set octet par valeur setcc.

Code objet (trois formats) :

Registre ou mémoire enregistrée :

|001110dw|modreg/m|

Valeur immédiate avec registre AX (AL) :

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

Valeur immédiate avec registre ou mémoire :

|100000sw|mod111r/m|--données--|données si sw=0|

DÉC
(Décrémenter l'opérande de 1)

Opérande décrémenté de un

^ Aperçu de la commande :

déc opérande

But : diminuer la valeur de l'opérande en mémoire ou registre de 1.

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

Application:
La commande 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 que la commande n'affecte pas l'indicateur cf.

Registre : |01001reg|

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

DIV
(DIVide non signé)

Section non signée

Schéma de commande :

diviseur div

Objectif : effectuer une opération de division sur deux valeurs binaires non signées.

^ Algorithme de travail :
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 est en octets, alors le dividende doit être situé dans le registre ax. Après l'opération, le quotient est mis en al et le reste en ah ;

si le diviseur est un mot, alors le dividende doit se situer dans le couple de registres dx:ax, avec la partie basse du dividende dans ax. Après l'opération, le quotient est mis en ax et le reste en dx ;

si le diviseur est un mot double, alors le dividende doit se situer dans le couple de registres edx:eax, avec la partie basse du dividende dans eax. Après l'opération, le quotient est placé dans eax et le reste dans edx.

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

Application:
La commande effectue une division entière des opérandes, renvoyant le résultat de la division sous forme de 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 d'une routine de service d'interruption

^ Aperçu de la commande :

int interruption_numéro

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

^ Algorithme de travail :

poussez le registre eflags/flags et l'adresse de retour sur la pile. Lors de l'écriture de l'adresse de retour, le contenu du registre de segment cs est d'abord écrit, puis le contenu du pointeur de commande eip/ip ;

remettre à zéro les drapeaux if et tf ;

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

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

Application:
Comme vous pouvez le voir dans la syntaxe, il existe deux formes de cette commande :

int 3 - a son propre opcode individuel 0cch et occupe un octet. Cette circonstance le rend très pratique à utiliser dans divers débogueurs de logiciels pour définir des points d'arrêt en remplaçant le premier octet de toute instruction. Le microprocesseur, rencontrant une commande avec l'opcode 0cch dans la séquence de commandes, appelle le gestionnaire d'interruption avec le vecteur numéro 3, qui sert à communiquer avec le débogueur logiciel.

La deuxième forme de l'instruction a une longueur de deux octets, a un opcode de 0cdh et vous permet d'initier un appel à une routine de service d'interruption avec un numéro de vecteur dans la plage 0-255. Les caractéristiques du transfert de contrôle, comme indiqué, dépendent du mode de fonctionnement du microprocesseur.

Code objet (deux formats) :

S'inscrire : |01000reg|

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

CCJ
JCXZ/JECXZ
(Sauter si condition)

(Sauter si CX=Zero/ Sauter si ECX=Zero)

Sauter si la condition est remplie

Sauter si CX/ECX est nul

^ Aperçu de la commande :

label jcc
étiquette jcxz
étiquette jecxz

Objectif : transition dans le segment actuel des commandes, en fonction de certaines conditions.

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

si la condition testée est vraie, aller à la cellule indiquée par l'opérande ;

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

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

si la condition vérifiée

Structure des instructions du langage d'assemblage La programmation au niveau des instructions machine est le niveau minimum auquel la programmation informatique est possible. Le système d'instructions de la machine doit être suffisant pour mettre en œuvre les actions requises en donnant des instructions au matériel de la machine. Chaque instruction machine se compose de deux parties : une partie opératoire qui définit « quoi faire » et un opérande qui définit les objets de traitement, c'est-à-dire « quoi faire ». L'instruction machine du microprocesseur, écrite en langage assembleur, est une ligne unique, ayant la forme suivante : étiquette instruction/instruction(s) opérande(s) ; 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 d'instruction sont séparés par des virgules.

Structure d'une instruction en langage assembleur Une instruction en langage assembleur indique au compilateur 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 spécifie la valeur initiale des données (dans le segment de données) ou les éléments sur lesquels l'instruction doit agir (dans le segment de code). Une instruction peut avoir un ou deux opérandes, ou aucun opérande. Le nombre d'opérandes est spécifié implicitement par le code d'instruction. Si la commande ou la directive doit être poursuivie 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 dans les commandes et les directives. Exemples de directives et de commandes Count db 1 ; Nom, directive, un opérande mov eax, 0 ; Commande, deux opérandes

Les identificateurs sont des séquences de caractères valides utilisés pour désigner des noms de variables et des noms d'étiquettes. L'identifiant peut être composé d'un ou plusieurs des caractères suivants : toutes les lettres de l'alphabet latin ; chiffres 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 commande) ne peuvent pas être utilisés comme identificateurs. Le premier caractère de l'identifiant doit être une lettre ou un caractère spécial. Longueur maximale identifiant 255 caractères, mais le traducteur accepte les 32 premiers, le reste est ignoré. 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 commencer à une position particulière dans la chaîne. Il est recommandé de les écrire dans une colonne pour une plus grande lisibilité du programme.

Étiquettes 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 commencer à une position particulière dans la chaîne. 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 d'instructions n'est pas clair. Les commentaires commencent sur n'importe quelle ligne d'un module source par un point-virgule (;). Tous les caractères à droite de " ; ' à la fin de la ligne sont des commentaires. Le commentaire peut contenir n'importe quel caractère imprimable, y compris "l'espace". Le commentaire peut s'étendre sur toute la ligne ou suivre la commande sur la même ligne.

Structure d'un programme en langage assembleur Un programme en langage assembleur peut être composé de plusieurs parties, appelées modules, chacune pouvant 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 principal, à partir duquel son exécution commence. 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. MODEL modifier memory_model, calling_convention, OS_type, stack_parameter Modèles de mémoire en langage assembleur de base : Modèle de mémoire Adressage de code Adressage de données système opérateur Entrelacement de code et de données TINY NEAR MS-DOS Autorisé SMALL NEAR MS-DOS, Windows Non MEDIUM FAR NEAR MS-DOS, Windows Non COMPACT NEAR FAR MS-DOS, Windows Non LARGE FAR MS-DOS, Windows Non HUGE FAR MS-DOS, Windows Non NEAR Windows 2000, Windows XP, Windows Autorisé FLAT NEAR 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 le code résident dans un seul segment physique. La taille du fichier programme dans ce cas 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 lors de l'utilisation de ce modèle sont traités comme proches (near). Le modèle moyen prend en charge plusieurs segments de code et un segment de données, avec tous les liens dans les segments de code considérés comme éloignés (loin) par défaut, et les liens dans le segment de données sont considérés comme proches (proche). Le modèle compact prend en charge plusieurs segments de données qui utilisent l'adressage des données distantes (far) et un segment de code qui utilise l'adressage des données proches (near). 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 de code et de données sont considérées 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 n'est utilisé que sur les systèmes d'exploitation 32 bits. Ce modèle est similaire au petit modèle en ce sens que les données et le code résident dans le même segment 32 bits. Développer un programme pour le modèle plat avant la directive. 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 commandes disponibles lors de l'écriture des programmes. La lettre p après la directive de sélection du processeur signifie un mode de fonctionnement protégé. L'adressage des données et du code est proche, toutes les adresses et tous les pointeurs étant de 32 bits.

modèles de mémoire. MODEL modifier memory_model, calling_convention, OS_type, stack_parameter Le paramètre modifier est utilisé pour définir les types de segment et peut prendre les valeurs suivantes : use 16 (les segments du modèle sélectionné sont utilisés en 16 bits) use 32 (les segments du modèle sélectionné sont utilisés comme 32 bits). Le paramètre calling_convention est utilisé pour déterminer comment les paramètres sont passés lors de l'appel d'une procédure à partir 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. MODÈLE modificateur memory_model, calling_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_param est défini sur : NEARSTACK (le registre SS est égal à DS, les régions 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 régions 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 "ne rien faire". 686 P. MODÈLE PLAT, STDCALL. DONNÉES. CODE DEBUT : RET FIN DEBUT RET - commande du microprocesseur. Il assure la fin correcte du programme. Le reste du programme est lié au fonctionnement du traducteur. . 686 P - Les commandes en mode protégé Pentium 6 (Pentium II) sont autorisées. Cette directive sélectionne le jeu d'instructions assembleur pris en charge en spécifiant le modèle de processeur. . MODEL FLAT, stdcall - modèle de mémoire plate. Ce modèle de mémoire est utilisé dans le système d'exploitation Windows. stdcall est la convention d'appel de procédure à utiliser.

Un exemple de programme "ne rien faire". 686 P. MODÈLE PLAT, STDCALL. DONNÉES. CODE DEBUT : RET FIN DEBUT . DATA - segment de programme contenant des données. Ce programme n'utilise pas la pile, donc segment. STACK est manquant. . CODE - un segment du programme contenant le code. DÉMARRER - étiquette. END START - la fin du programme et un message au compilateur indiquant que le programme doit être démarré à partir de l'étiquette START. Chaque programme doit contenir une directive END marquant la fin code source programmes. Toutes les lignes qui suivent la directive END sont ignorées. L'étiquette après la directive END indique au compilateur 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 assembleur Un traducteur est un programme ou moyens techniques A qui convertit un programme 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 macros, souvent incompatibles avec quoi que ce soit d'autre. Les principaux types de traducteurs de langage d'assemblage sont : MASM (Microsoft Assembler), TASM (Borland Turbo Assembler), FASM (Flat Assembler) - un assembleur multi-passes librement distribué écrit par Tomasz Gryshtar (polonais), NASM (Netwide Assembler) - un L'assembleur libre 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éveloppement chez Source. Forger. filet.

Src="https://present5.com/presentation/-29367016_63610977/image-15.jpg" alt="Traduction du programme dans Microsoft Visual Studio 2005 1) Créez un projet en sélectionnant Fichier->Nouveau->Projet MenuEt"> Трансляция программы в 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="Program translation in Microsoft Visual Studio 2005 2) Dans l'arborescence du projet (View->Solution Explorer) 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. asm :

Traduction du programme dans Microsoft Visual Studio 2005 5) Définir les options du compilateur. Sélectionnez sur le bouton droit dans le menu du fichier de projet Custom Build Rules…

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

Traduction du programme en Microsoft Visual Studio 2005 Vérifier par le bouton droit dans le fichier bonjour. asm de l'arborescence du projet dans le menu Propriétés et définissez Général->Outil : Microsoft Macro Assembler.

Src="https://present5.com/presentation/-29367016_63610977/image-22.jpg" alt="Program translation in 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 OS Windows La programmation sous OS Windows repose sur l'utilisation de fonctions API (Application Program Interface, c'est-à-dire l'interface d'application logicielle). Leur nombre atteint 2000. Le programme pour Windows se compose en grande partie de tels appels. Toutes les interactions avec périphériques externes et les ressources du système d'exploitation se produit, en règle générale, à travers ces fonctions. salle d'opération Système Windows utilise un modèle de mémoire plat. L'adresse de n'importe quel emplacement de 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être, cadre).

Appel Fonctionnalités Windows API Dans le fichier d'aide, toute fonction API est représentée par le type nom_fonction (FA 1, FA 2, FA 3) Type – type de valeur de retour ; FAX – liste des arguments formels dans leur ordre. Par exemple, int Message. Boîte (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Cette fonction affiche une fenêtre avec un message et un ou plusieurs boutons de sortie. Signification des paramètres : h. Wnd - handle de la fenêtre dans laquelle la fenêtre de message apparaîtra, lp. Texte - le 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, en particulier, vous pouvez spécifier le nombre de boutons de sortie.

Appel des fonctions de l'API Windows dans Message. Boîte (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Presque tous les paramètres de la fonction API sont en fait des entiers 32 bits : HWND est un entier 32 bits, LPCTSTR est un pointeur de chaîne 32 bits, UINT est un entier 32 bits. Le suffixe "A" est souvent ajouté au nom des fonctions pour accéder aux versions plus récentes des fonctions.

Appel des fonctions de l'API Windows dans Message. Boîte (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Lorsque vous utilisez MASM, vous devez ajouter @N N à la fin du nom - le nombre d'octets que les arguments passés occupent sur la pile. Pour les fonctions API Win 32, ce nombre peut être défini comme le nombre d'arguments n fois 4 (octets dans chaque argument) : N=4*n. Pour appeler une fonction, l'instruction CALL de l'assembleur est utilisée. Dans ce cas, tous les arguments de la fonction lui sont passés via la pile (commande PUSH). Sens de passage des arguments : DE GAUCHE À DROITE - DE BAS EN HAUT. L'argument u sera d'abord poussé sur la pile. taper. L'appel de la fonction spécifiée ressemblera à ceci : CALL Message. boîte. [courriel protégé]

Appel des fonctions de l'API Windows dans Message. Boîte (HWND h. Wnd, LPCTSTR lp. Text, LPCTSTR lp. Caption, UINT u. Type); Le résultat de l'exécution de toute fonction API est généralement un nombre entier, qui est renvoyé dans le registre EAX. La directive OFFSET est un "décalage de segment" ou, en termes de langage de haut niveau, un "pointeur" vers le début d'une chaîne. La directive EQU, comme #define en C, définit une constante. La directive EXTERN indique au compilateur qu'une fonction ou un identifiant est externe au module.

Un exemple du programme "Bonjour tout le monde!" . 686 P. MODÈLE PLAT, STDCALL. PILE 4096. DATA MB_OK EQU 0 STR 1 DB "Mon premier programme", 0 STR 2 DB "Bonjour à tous !", 0 HW DD ? Message EXTERNE. boîte. [courriel protégé]: PRÈS. CODE START : APPUYEZ SUR MB_OK APPUYEZ SUR OFFSET STR 1 APPUYEZ SUR OFFSET STR 2 APPUYEZ Message APPEL HW. boîte. [courriel protégé] RET FIN DEBUT

La directive INVOKE Le traducteur de langage MASM permet également de simplifier l'appel de fonction à 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 où ils sont donnés dans la description de la fonction. les macros de traduction poussent les paramètres sur la pile. pour utiliser la directive INVOKE, vous devez avoir une description du prototype de la fonction utilisant la directive PROTO sous la forme : Message. boîte. UN PROTO : DWORD, : DWORD

Sujet 2.5 Notions de base sur la programmation du processeur

Au fur et à mesure que la durée du programme augmente, il devient plus difficile de se souvenir des codes pour diverses opérations. Les mnémoniques fournissent une aide à cet égard.

Le langage d'encodage des instructions symboliques est appelé assembleur.

langage d'assemblage est un langage dans lequel chaque instruction correspond exactement à une instruction 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'inclure des programmes de bibliothèque et générer des séquences d'instructions symboliques en spécifiant des paramètres spécifiques dans les micro-instructions. Ce programme est généralement placé dans la ROM ou entré dans la RAM à partir d'un support externe.

Le langage d'assemblage a plusieurs caractéristiques qui le distinguent des langages de haut niveau :

1. Il s'agit d'une correspondance un à un entre les instructions en langage assembleur et les instructions machine.

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

Une compréhension des bases de la programmation dans les langages orientés machine est utile pour :



Meilleure compréhension de l'architecture des PC et meilleure utilisation 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 ces programmes dans le débogueur de programme DEBUG et en décompilant leur affichage en langage d'assemblage );

Compilation de programmes pour résoudre les tâches les plus critiques (un programme compilé dans un langage orienté machine est généralement plus efficace - plus court et plus rapide de 30 à 60% que les programmes obtenus à la suite d'une traduction à partir de langages de haut niveau)

Pour la mise en œuvre des procédures incluses dans le programme principal en tant que fragments séparés dans le cas où elles ne peuvent être mises en œuvre 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 des ordinateurs de la même famille, tandis qu'un programme écrit dans un langage de haut niveau peut potentiellement s'exécuter sur des machines différentes.

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

Les nombres ne sont que des entiers. Distinguer:

Nombres binaires se terminant par la lettre B ;

Nombres décimaux se terminant par D ;

Nombres hexadécimaux se terminant par la lettre N.

RAM, registres, représentation des données

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

Le langage d'assemblage 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 les capacités d'une machine particulière (plus précisément, MP) de manière plus rationnelle qu'un programme dans un langage de haut niveau (ce qui est plus facile pour un programmeur que pour un assembleur). Nous examinerons les principes de base de la programmation dans des langages orientés machine en utilisant le langage d'assemblage pour MP KR580VM80 à titre d'exemple. Pour la programmation dans le langage, une technique générale est utilisée. Des techniques spécifiques d'enregistrement de programmes sont liées à l'architecture et aux caractéristiques du système de commande du MP cible.

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

Le modèle de programme du MPS selon la figure 1

Mémoire des ports MP

S Z CA P C

Image 1

Du point de vue du programmeur, le KR580VM80 MP possède les registres suivants accessibles au programme.

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

B, C, D, E, H, L– Registres à usage général 8 bits (RON). 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 à partir des registres, des paires BC, DE, HL sont formées et le double registre est appelé la première lettre - B, D, H. Dans la paire de registres, le premier registre est le plus élevé. Les registres H, L, utilisés à la fois pour stocker des données et pour stocker des adresses 16 bits de cellules RAM, ont une propriété particulière.

Floride– registre d'indicateurs (registre de caractéristiques) Un registre de 8 bits qui stocke cinq caractéristiques du résultat d'opérations arithmétiques et logiques dans le MP. Format FL conforme à la photo

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

Bit P (parité) - parité, est mis à 1 si le nombre d'unités dans les bits du résultat est pair.

Le bit AC est un report supplémentaire, conçu pour stocker la valeur de report de la tétrade inférieure du résultat.

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

Le 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, est conçu pour stocker l'adresse de l'emplacement mémoire où le dernier octet entré sur la pile a été écrit.

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

Dans la zone de mémoire initiale de l'adresse 0000H - 07FF se trouve 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'enregistrement des données. (RAM).

0BB0 est l'adresse de départ de la pile. (RAM).

Stack est une zone spécialement organisée de RAM conçue pour le stockage temporaire de données ou d'adresses. Le dernier numéro poussé sur la pile est le premier numéro sorti de la pile. Le pointeur de pile stocke l'adresse du dernier emplacement de pile où les informations sont stockées. Lorsqu'un sous-programme est appelé, l'adresse de retour au 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 stocké 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 d'assemblage

La mémoire MP KR580VM80 est un tableau de mots de 8 bits appelés octets.Chaque octet a sa propre adresse de 16 bits qui détermine sa position dans la séquence des cellules mémoire. Le MP peut adresser 65536 octets de mémoire, qui peuvent contenir à la fois de la ROM et de la RAM.

Format de 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 le moins significatif est le bit 0, le bit le plus significatif est le bit 7.

La commande est caractérisée par le 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 instructions multi-octets doivent être placées dans des PL voisins. Le format de la commande dépend des spécificités de l'opération en cours d'exécution.

Le premier octet de la commande contient l'opcode écrit sous forme mnémonique.

Il définit le format de la 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 la localisation des données.

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

Format de commande à un octet selon la figure 2

Figure 4

Dans les instructions en langage assembleur, l'opcode 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 l'exécution, le programme source est traduit à l'aide d'un programme de traduction, appelé assembleur, dans le langage des combinaisons de codes - langage machine, sous cette forme il est placé dans la mémoire du MP puis 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 se trouver dans les registres internes du MP (le plus pratique et choix rapide). Ils peuvent être situés dans la mémoire système (l'option la plus courante). Enfin, ils peuvent être dans des périphériques d'E/S (cas le plus rare). L'emplacement des opérandes est déterminé par le code d'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ù mettre l'opérande de sortie. Ces méthodes sont appelées méthodes d'adressage.

Pour MP KR580VM80, il existe les méthodes d'adressage suivantes :

Immédiat;

Enregistrer;

indirect;

Empiler.

Immédiat l'adressage suppose que l'opérande (entrée) est 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 les deuxième ou deuxième et troisième octets de la commande, avec l'octet de données bas dans le deuxième octet de commande et l'octet de données haut dans le troisième octet de commande.

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

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

Indirect L'adressage (implicite) suppose que le registre interne du MP n'est 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 aux cellules mémoire par le contenu du registre SP 16 bits (pointeur de pile).

Système de commande

Le système de commande MP est une liste complète d'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 (y compris les modifications 244).

Il existe 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 travail avec la pile.


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

Symbole Réduction
ADDR Adresse 16 bits
DONNÉES Données 8 bits
DONNÉES 16 Données 16 bits
PORT Adresse d'E/S 8 bits (périphériques d'E/S)
OCTET 2 Deuxième octet de commande
OCTET 3 Troisième octet de commande
R, R1, R2 Un des registres : A, B, C, D, E, H, L
PR L'une des paires de registres : B - définit une paire d'aéronefs ; D - définit une paire de DE ; H - spécifie une paire de HL
HR Premier registre de la paire
RL Deuxième registre de la paire
Λ Multiplication booléenne
V Addition booléenne
Addition modulo deux
M Cellule de mémoire dont l'adresse spécifie le contenu de la paire de registres HL, c'est-à-dire M = (HL)



Haut