Contacts

Commandes en langage assembleur. Informations de base sur le langage assembleur. Sur la discipline "Programmation système Programme en langage assembleur

L'UNIVERSITÉ NATIONALE D'OUZBÉKISTAN PORTE LE NOM DE MIRZO ULUGBEK

FACULTÉ DE TECHNOLOGIE INFORMATIQUE

Sur le thème : Analyse sémantique d'un fichier EXE.

Complété:

Tachkent 2003.

Avant-propos.

Langage d'assemblage et structure de commande.

Structure de fichier EXE (analyse sémantique).

Structure de fichier COM.

Le principe de fonctionnement et de propagation du virus.

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 touche à l'activité humaine n'est pas complet sans la technologie informatique. Et cela contribue à son développement élevé et à sa perfection. Bien que le développement des ordinateurs personnels ait commencé il n'y a pas si longtemps, des pas colossaux ont été franchis dans les produits logiciels et pendant longtemps, ces produits seront largement utilisés. Le domaine de la connaissance informatique a explosé, tout comme la technologie connexe. Si vous ne tenez pas compte du côté commercial, alors on peut dire qu'il n'y a pas d'étrangers dans ce domaine d'activité professionnelle. De nombreuses personnes sont engagées dans le développement de programmes sans but lucratif ou lucratif, mais de leur propre gré, par passe-temps. Bien sûr, cela ne devrait pas affecter la qualité du programme, et dans ce métier, pour ainsi dire, "business", il y a concurrence et demande de performances de qualité, de travail stable et répondant à toutes les exigences de notre temps. Il faut aussi noter ici l'émergence des microprocesseurs dans les années 60, qui sont venus remplacer un grand nombre de jeux de lampes. Certains types de microprocesseurs sont très différents les uns des autres. Ces microprocesseurs diffèrent les uns des autres par la taille des bits et les 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 prolifération des micro-ordinateurs a incité à repenser le 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 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 professionnels du logiciel développent dans des langages de haut niveau tels que Pascal, C ou Delphi, qui sont plus faciles à écrire des programmes, le logiciel le plus puissant et le plus efficace est écrit en tout ou en partie en langage assembleur. Des langages de haut niveau ont été développés pour éviter la technicité particulière de certains ordinateurs. 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 particulier, il faut connaître son architecture. Aujourd'hui, le principal produit logiciel est le fichier EXE. Compte tenu des aspects positifs de cela, l'auteur du programme peut être sûr de son intégrité. Mais parfois, ce n'est souvent pas le cas. Il y a aussi un désassembleur. À l'aide d'un désassembleur, vous pouvez découvrir les interruptions et les codes de programme. Il ne sera pas difficile pour une personne maîtrisant bien le langage assembleur de refaire tout le programme à sa guise. C'est peut-être de là que vient le problème le plus insoluble - le virus. Pourquoi les gens écrivent-ils un virus ? Certaines personnes posent cette question avec surprise, d'autres avec colère, mais néanmoins, il y a encore des personnes qui s'intéressent à cette tâche non pas du point de vue de causer du mal, mais en tant qu'intérêt pour la programmation du système. Les virus écrivent pour diverses raisons. Certaines personnes aiment les appels système, d'autres aiment améliorer leurs connaissances en assembleur. Je vais essayer de décrire tout cela dans ma dissertation. Il parle également non seulement de la structure du fichier EXE, mais aussi du langage assembleur.

^ Langage d'assemblage.

Il est intéressant de retracer, depuis les premiers ordinateurs jusqu'à nos jours, les transformations de la compréhension du langage assembleur chez les programmeurs.

Il était une fois, l'assembleur était un langage, sans la connaissance duquel il était impossible de faire faire quoi que ce soit d'utile à un ordinateur. La situation a progressivement 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, essayons de comprendre ce qu'est le langage assembleur en général.

En bref, le langage assembleur est une représentation symbolique d'un langage machine. Tous les processus de la machine au niveau matériel le plus bas ne sont pilotés que par des commandes de langage machine (instructions). Par conséquent, il est clair que, malgré le nom général, le langage d'assemblage pour chaque type d'ordinateur est différent. Cela vaut également pour l'apparition de programmes écrits en langage assembleur, et les idées dont ce langage est le reflet.

Il est impossible de vraiment résoudre les problèmes liés au matériel (ou même, de plus, les problèmes liés au matériel tels que l'amélioration des performances du programme) sans connaître l'assembleur.

Un programmeur ou tout autre utilisateur peut utiliser n'importe quel moyen de haut niveau, jusqu'aux programmes de construction de mondes virtuels, et peut même ne pas se douter qu'en fait l'ordinateur n'exécute pas les commandes du langage dans lequel son programme est écrit, mais leur transformation représentation sous la forme de séquences ennuyeuses et ennuyeuses de commandes d'un langage complètement différent - la machine. Imaginons maintenant qu'un tel utilisateur ait un problème non standard ou que quelque chose ne va pas. Par exemple, son programme doit fonctionner avec un périphérique inhabituel ou effectuer d'autres actions nécessitant une connaissance des principes du matériel informatique. Peu importe à quel point le 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 généralistes en informatique est déjà révolu. Comme on dit, on ne peut pas saisir l'immensité. Mais il y a quelque chose en commun, une sorte de fondation sur laquelle toute formation informatique sérieuse est construite. Il s'agit de connaissances sur les principes 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).

Figure. 1. Ordinateur et périphériques

Figure. 2. Schéma fonctionnel d'un ordinateur personnel

À partir de 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é centrale. Logiquement parlant, il est clair qu'il joue le rôle d'une sorte de dispositif de coordination. Jetons un coup d'œil à l'intérieur de l'unité centrale (inutile d'essayer de pénétrer à l'intérieur du moniteur - il n'y a rien d'intéressant là-bas, et 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, examinons le schéma fonctionnel d'un ordinateur typique (Fig. 2). Il ne prétend pas être une précision inconditionnelle et vise uniquement à montrer le but, l'interconnexion et la composition typique des éléments d'un ordinateur personnel moderne.

Discutons du circuit de la fig. 2 dans un style quelque peu non conventionnel.
Il est naturel pour une personne, lorsqu'elle rencontre quelque chose de nouveau, de rechercher des associations qui peuvent l'aider à apprendre l'inconnu. Quelles associations provoque un ordinateur ? 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 similaire à lui-même. L'ordinateur a des organes pour percevoir les informations du monde extérieur - c'est un clavier, une souris, des lecteurs de disques magnétiques. En figue. 2 ces organes sont situés à droite des bus du système. L'ordinateur possède des organes "digérant" les informations reçues - ce sont le processeur central et la mémoire vive. Et enfin, l'ordinateur possède des organes de la parole qui produisent les résultats du traitement. Ce sont également quelques-uns des appareils sur la droite.

Les ordinateurs modernes, bien sûr, sont loin d'être humains. Ils peuvent être comparés à des créatures 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 élevé de communication avec un ordinateur, tout se résume en fin de compte à une séquence ennuyeuse et monotone d'instructions machine.
Chaque commande machine est une sorte de stimulus pour l'excitation de l'un ou l'autre réflexe inconditionné. La réponse à ce stimulus est toujours univoque et est « câblée » dans le bloc de microinstructions sous la forme d'un microprogramme. Ce microprogramme met en oeuvre des actions pour mettre en oeuvre une commande machine, mais déjà au niveau des signaux fournis à certains circuits logiques du calculateur, contrôlant ainsi différents sous-systèmes du calculateur. C'est ce qu'on appelle le principe du contrôle par microprogramme.

Poursuivant l'analogie avec les humains, 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é selon certaines règles estomac (ordinateur). Seul l'estomac de l'ordinateur aime la nourriture diététique et monotone - 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 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 dans les années 50, les programmeurs ont commencé à utiliser pour programmer un analogue symbolique d'un langage machine, qu'ils appelaient langage d'assemblage. 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 puisque le langage assembleur est "natif" pour un ordinateur, le programme le plus efficace ne peut être écrit que dedans (à 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é, ils écrivent principalement des programmes en assembleur qui devraient assurer un travail efficace avec le matériel. Parfois, des parties du programme qui sont critiques en termes de temps d'exécution ou de consommation de mémoire sont écrites en langage assembleur. Par la suite, ils sont formatés en sous-programmes et combinés avec un code de 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 est laissée visible et accessible pour la programmation dans ce langage. C'est ce qu'on appelle le modèle logiciel d'un ordinateur, dont une partie est un modèle logiciel d'un microprocesseur, qui contient 32 registres, d'une manière ou d'une autre, disponibles pour être utilisés par un programmeur.

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

^ 16 registres d'utilisateurs;

16 registres système.

Dans les programmes en langage assembleur, les registres sont très utilisés. La plupart des registres ont un objectif fonctionnel spécifique.

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

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

registres d'état et de contrôle :

Drapeaux de registre de drapeaux/drapeaux ;

Le registre du pointeur de commande eip/ip.

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

Pourquoi beaucoup de ces registres sont-ils représentés avec des séparateurs 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 comme objets séparés dans le programme. Ceci est fait pour garantir l'opérabilité des programmes écrits pour les modèles bas de gamme 16 bits de microprocesseurs Intel, à commencer par i8086. Les microprocesseurs i486 et Pentium ont pour la plupart des registres de 32 bits. Leur nombre, à l'exception des registres de segment, est le même que dans le i8086, mais la dimension est plus grande, ce qui se reflète dans leurs désignations - ils ont
le 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 plus jeunes de 16 bits de microprocesseurs Intel.

Listons les registres appartenant au groupe de 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 de l'accumulateur) - batterie.
Il est 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.
Il est 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 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 la boucle, en plus de transférer le contrôle à la 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 des 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 de chaînage, c'est-à-dire les opérations qui effectuent un traitement séquentiel de chaînes d'éléments, dont chacune peut avoir une longueur de 32, 16 ou 8 bits :

esi / si (registre d'index de source) - index de source.
Ce registre dans les opérations de chaînage 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 de chaînage contient l'adresse courante dans la chaîne de destination.

Dans une architecture à microprocesseur, une structure de données telle qu'une pile est prise en charge au niveau du micrologiciel. Pour travailler avec la pile dans le système de commande 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 le pointeur vers le haut de la pile dans le segment de pile actuel.

ebp / bp (Base Pointer register) - registre du pointeur de la base de la 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 d'un programme pour le stockage temporaire de données arbitraires. Bien entendu, les données peuvent être stockées dans le segment de données, mais dans ce cas, pour chaque donnée stockée pour l'instant, 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é d'une pile est que sa portée est réutilisable et que les données sont stockées dans la pile et récupérées à partir de là à l'aide des 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 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 extrait de la pile au retour du sous-programme. Une autre technique courante consiste à transmettre les paramètres dont il a besoin via la pile à un sous-programme. Le sous-programme, connaissant l'ordre dans lequel les paramètres sont poussés sur la pile, peut les prendre à partir de là et les utiliser lors de son exécution. Une particularité de la pile est une sorte d'ordre de récupération des données qu'elle contient : à tout moment, seul l'élément du haut est disponible dans la pile, c'est-à-dire le dernier élément poussé sur la pile. Le déchargement de l'élément supérieur de la pile rend l'élément suivant disponible. Les éléments de pile sont situés dans la zone mémoire allouée à la pile, en partant du bas de la pile (c'est-à-dire à partir de son adresse maximale) à des 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 mémoire de programme, la pile doit entrer 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 segment de pile SS. Ainsi, la paire de registres SS : SP décrit l'adresse de la cellule de pile disponible : SS stocke l'adresse de segment de la pile, et SP stocke l'offset des dernières données stockées dans la pile (Fig. 4, a). Faites 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 déchargement de deux articles et retour à l'état d'origine.

Le chargement dans la pile est effectué par une commande spéciale d'opération de pile (push). Cette commande 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 sauvegarder 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 le haut (vers les adresses inférieures) et l'opérande spécifié dans la commande push est écrit à cette adresse. Le chargement suivant sur la commande stack, par exemple,

mettra la pile dans l'état illustré à la Fig. 1.10, ch. La pile va maintenant stocker deux éléments, et seul celui du haut, vers lequel pointe le pointeur de pile SP, sera disponible. Si, après un certain temps, nous devons restaurer le contenu d'origine des registres stockés sur la pile, nous devons exécuter des commandes pop :

pop DS
pop AX

Quelle doit être la taille de la pile ? Cela dépend de l'intensité de son utilisation dans le programme. Si, par exemple, vous prévoyez 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 DOS y envoie le contenu des registres et d'autres informations liées au programme interrompu. Par conséquent, même si le programme n'utilise pas du tout la pile, elle doit toujours être présente dans le programme et avoir une taille d'au moins plusieurs dizaines de mots. Dans notre premier exemple, nous avons mis 128 mots sur la pile, ce qui est certainement suffisant.

^ La structure d'un programme en langage assembleur

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 un ensemble de phrases de langage, dont chacune occupe une ligne distincte de code de programme.

Les phrases d'assemblage sont de quatre types :

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

les macros sont des phrases du texte du programme qui sont formées d'une certaine manière, qui sont remplacées lors de la diffusion par d'autres phrases ;

directives qui demandent au traducteur assembleur d'effectuer certaines actions. Les directives n'ont pas d'analogue 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 assembleur

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

Figure. 5. Format de la phrase assembleur

Figure. 6. Format des directives

Figure. 7. Format des commandes et des macros

Dans ces chiffres :

label name est un identifiant dont la valeur est l'adresse du premier octet de la phrase du texte source du programme qu'il désigne ;

name est un identifiant qui distingue cette directive des autres directives du même nom. A la suite du traitement d'une certaine directive par l'assembleur, certaines caractéristiques peuvent être affectées à ce nom ;

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

Les opérandes sont des parties d'une instruction, d'une macro ou d'une directive d'assembleur qui désignent les objets à manipuler. Les opérandes assembleur sont décrits par des expressions avec des constantes numériques et textuelles, des étiquettes et des identificateurs de variables utilisant des signes d'opération et quelques mots réservés.

^ Comment utiliser les diagrammes de syntaxe ? C'est très simple : il suffit de trouver puis de passer de l'entrée du schéma (à gauche) à sa sortie (à droite). Si un tel chemin existe, alors la phrase ou la construction est syntaxiquement correcte. S'il n'y a pas un tel chemin, alors 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, il peut y avoir ceux qui peuvent être suivis de droite à gauche. En fait, les diagrammes de syntaxe 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 du programme sont :

Toutes les lettres latines : 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 d'assembleur sont formées à partir de jetons, qui sont des séquences syntaxiquement inséparables de caractères valides dans la langue qui ont un sens pour un traducteur.

Les jetons sont :

les identificateurs sont des séquences de caractères valides utilisées 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 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 - _,?, $, @. L'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 de 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 assembleur.

Les commandes assembleur révèlent 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 logicielle. Cependant, les tâches programmables sont rarement aussi faciles. 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 de plusieurs actions effectuer. Certaines commandes peuvent transférer le contrôle en changeant 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 instructions pour différents processeurs, mais nous allons considérer un certain nombre d'instructions 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 un exemple d'un tableau qui reflète la structure du registre eflags :

La ligne du bas de ce tableau répertorie les valeurs de drapeau après l'exécution de la commande. Dans ce cas, les désignations 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 effacé (é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 n'est pas défini ;

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

Les conventions suivantes sont utilisées pour représenter les opérandes dans les diagrammes de syntaxe :

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

m8, m16, m32, m48 - octet, mot, double mot ou opérande mémoire 48 bits ;

i8, i16, i32 - opérande immédiat d'octet, de mot ou de 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
(Une addition)

Une addition

^ Schéma de commande :

ajouter destination, source

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

Algorithme de travail :

ajouter les opérandes source et destination ;

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

mettre des drapeaux.

L'état des drapeaux après l'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 est en dehors des limites de l'opérande récepteur (un débordement se produit), alors cette situation doit être prise en compte en analysant le drapeau cf et l'utilisation possible ultérieure de la commande adc. Par exemple, ajoutez les valeurs dans ax et ch. L'ajout doit 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 | --data-- | données si w = 1 |

Registre ou mémoire plus valeur immédiate :

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

APPEL
(APPEL)

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

^ Schéma de commande :

Objectif:

transfert de contrôle à une procédure proche ou distante avec stockage de l'adresse du point de retour dans la pile ;

commutation de tâches.

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

Près de l'étiquette - 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 ;

Far label - le contenu des pointeurs 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 un emplacement mémoire contenant des décalages dans le segment d'instruction en cours 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 drapeaux changent en fonction des informations du registre des drapeaux dans le segment d'état TSS de la tâche vers laquelle basculer.
Application:
La commande d'appel vous permet d'organiser un transfert de contrôle flexible et multivarié vers un sous-programme tout en conservant l'adresse du point de retour.

À propos du code objet (quatre formats) :

Adressage direct des segments :

| 11101000 | disp-bas | diep-haut |

Adressage de segment indirect :

| 11111111 | mod010r / m |

Adressage indirect entre segments :

| 11111111 | mod011r / m |

Adressage direct entre segments :

| 10011010 | offset-bas | offset-haut | seg-bas | seg-haut |

CMP
(Comparer les opérandes)

Comparaison des 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 stockez pas le résultat).

Application:
Cette commande est utilisée pour soustraire deux opérandes sans changer les opérandes. Les drapeaux sont définis en fonction des résultats de l'exécution de la commande. La commande cmp est utilisée avec les commandes de branchement conditionnel et la commande octet par valeur setcc.

A propos du code objet (trois formats) :

Registre ou mémoire avec registre :

| 001110dw | modregr / m |

Valeur directe avec registre AX (AL) :

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

Valeur immédiate avec registre ou mémoire :

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

DÉC
(Opérande DÉcrémenter de 1)

Diminuer l'opérande de un

^ Schéma de commande :

opérande déc

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. L'état des drapeaux après l'exécution de la commande :

Application:
La commande dec permet de décrémenter la valeur d'un octet, d'un mot, d'un double mot en mémoire ou dans un registre de un. Notez, cependant, que la commande n'affecte pas le drapeau cf.

S'inscrire : |01001reg |

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

DIV
(DIVISER non signé)

Division non signée

Schéma de commande :

diviseur div

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

^ Algorithme de travail :
Pour la commande, vous devez spécifier deux opérandes - le dividende et le diviseur. Le dividende est défini implicitement et sa taille dépend de la taille du diviseur, qui est spécifiée dans la commande :

si le diviseur est la taille de l'octet, alors le dividende doit être situé dans le registre des haches. Après l'opération, le quotient est placé dans al, et le reste dans ah ;

si le diviseur est un mot, alors le dividende doit être situé dans une paire de registres dx : ax, et la partie la moins significative du dividende est en ax. Après l'opération, le quotient est placé en ax, et le reste est en dx ;

si le diviseur est un mot double, alors le dividende doit être situé dans le couple de registres edx:eax, avec la partie la moins significative du dividende en eax. Après l'opération, le quotient est mis en eax, et le reste est mis en edx.

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

Application:
La commande effectue une division entière des opérandes avec la sortie du résultat de la division en tant que quotient et 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.

A propos du code objet :

| 1111011w | mod110r / m |

INT
(Interrompre)

Appel d'une routine de 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 d'instruction.

^ Algorithme de travail :

poussez le registre flags / flags et l'adresse de retour sur la pile. Lors de l'écriture de l'adresse de retour, le contenu du registre du segment 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 gestionnaire 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 à partir de la syntaxe, il existe deux formes de cette commande :

int 3 - a son propre opcode individuel 0cch et occupe un octet. Ce fait le rend très pratique pour une utilisation dans divers débogueurs logiciels pour définir des points d'arrêt en substituant le premier octet de n'importe quelle commande. Le microprocesseur, rencontrant dans la séquence de commandes une commande avec un opcode de 0cch, appelle le programme gestionnaire d'interruptions avec le vecteur numéro 3, qui est utilisé pour communiquer avec le débogueur logiciel.

La deuxième forme de la commande prend deux octets, a un code opération de 0cdh et vous permet d'initier un appel à une routine de service d'interruption avec un numéro de vecteur compris entre 0 et 255. Les caractéristiques du transfert de contrôle, comme indiqué, dépendent du mode de fonctionnement du microprocesseur.

A propos du code objet (deux formats) :

S'inscrire : |01000reg |

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

JCC
JCXZ / JECXZ
(Sauter si condition)

(Saut si CX = Zéro / Saut 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 actuel de commandes, en fonction d'une certaine condition.

^ Algorithme de commandes (sauf pour jcxz / jecxz) :
Vérification de l'état des drapeaux en fonction du code d'opération (il reflète la condition vérifiée) :

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

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

Algorithme de la 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

Sujet 1.4 Mnémoniques de l'assembleur. Structure et formats des commandes. Types d'adressage. Jeu de commandes du microprocesseur

Plan:

1 Langage assembleur. Concepts de base

2 Symboles du langage assembleur

3 types d'instructions assembleur

4 Directives de montage

5 Jeu d'instructions du processeur

1 jelangage d'assemblage. Concepts de base

Langage d'assemblageest 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 de langage machine (instructions). Par conséquent, il est clair que, malgré le nom général, le langage d'assemblage pour chaque type d'ordinateur est différent.

Un programme en 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 un ensemble de phrases de langage, dont chacune occupe une ligne distincte de code de programme.

Les phrases d'assemblage sont de quatre types :

1) commandes ou instructions, qui sont des analogues symboliques des instructions machine. Dans le processus de traduction, les instructions assembleur sont converties en les commandes correspondantes du jeu d'instructions du microprocesseur ;

2) macros -des phrases du texte du programme qui sont formées d'une certaine manière, qui sont remplacées lors de la diffusion par d'autres phrases ;

3) directives,qui sont des instructions au traducteur assembleur pour effectuer certaines actions. Les directives n'ont pas d'analogue dans la représentation machine ;

4) lignes de commentaires contenant des symboles, y compris les lettres de l'alphabet russe. Les commentaires sont ignorés par le traducteur.

­ La structure d'un programme assembleur. Syntaxe d'assemblage.

Les phrases qui composent le programme peuvent être une construction syntaxique correspondant à une commande, une macro, une directive ou un commentaire. Pour que le traducteur assembleur puisse les reconnaître, ils doivent être formés selon certaines règles syntaxiques. La meilleure façon de le faire est d'utiliser une description formelle de la syntaxe du langage comme des règles de grammaire. Les manières les plus courantes de décrire un langage de programmation comme celui-ci - diagrammes de syntaxe et formes Backus-Naur étendues. Plus pratique pour une utilisation pratique diagrammes de syntaxe. Par exemple, la syntaxe des phrases en assembleur peut être décrite à l'aide des diagrammes de syntaxe illustrés dans les figures 10, 11, 12.

Figure 10 - Format de phrase d'assemblage


­ Figure 11 - Format des directives

­ Figure 12 - Format des commandes et des macros

Dans ces chiffres :

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

­ Nom -identifiant qui distingue cette directive des autres directives du même nom. A la suite du traitement d'une certaine directive par l'assembleur, certaines caractéristiques peuvent être affectées à ce nom ;

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

­ opérandes -parties d'une commande, d'une macro ou d'une directive d'assembleur qui désignent les objets à manipuler. Les opérandes assembleur sont décrits par des expressions avec des constantes numériques et textuelles, des étiquettes et des identificateurs de variables utilisant des signes d'opération et quelques mots réservés.

Aide des diagrammes de syntaxe trouver puis passer de l'entrée du schéma (à gauche) à sa sortie (à droite). Si un tel chemin existe, alors la phrase ou la construction est syntaxiquement correcte. S'il n'y a pas un tel chemin, alors le compilateur n'acceptera pas cette construction.

­ 2 Symboles du langage assembleur

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

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

2) nombres de 0 avant que 9 ;

3) signes ? , @ , $ , _ , & ;

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

Les phrases en assembleur sont formées à partir de jetons, qui sont des séquences syntaxiquement inséparables de caractères valides de la langue et significatives pour le traducteur.

Lexèmes sont:

1) identifiants - séquences de caractères valides utilisées pour désigner les objets du programme tels que les opcodes, les noms de variables et les noms d'étiquettes. La règle d'écriture des identifiants est la suivante : un identifiant peut être constitué d'un ou plusieurs caractères ;

2) chaînes de caractères - séquences de caractères entre guillemets simples ou doubles ;

3) nombres entiers de l'un des systèmes de nombres suivants : binaire, décimal, hexadécimal. L'identification des nombres lors de leur écriture dans des programmes en langage assembleur s'effectue selon certaines règles :

4) les nombres décimaux ne nécessitent aucun symbole supplémentaire pour leur identification, par exemple 25 ou 139. Pour l'identification dans le code source du programme nombres binaires après avoir écrit les zéros et les uns inclus dans leur composition, il faut mettre le latin " b”, Par exemple 10010101 b.

5) les nombres hexadécimaux ont plus de conventions lorsqu'ils s'écrivent :

Premièrement, ils sont constitués de nombres 0...9 , lettres minuscules et majuscules de l'alphabet latin une,b, c,,e,F ou alors UNE,B,C,,E,F.

Deuxièmement, le traducteur peut avoir des difficultés à reconnaître les nombres hexadécimaux du fait qu'ils peuvent être constitués soit uniquement de chiffres 0 ... 9 (par exemple, 190845), soit commencer par une lettre de l'alphabet latin (par exemple, ef15). Afin "d'expliquer" au traducteur qu'un jeton donné n'est pas un nombre décimal ou un identifiant, le programmeur doit sélectionner un nombre hexadécimal d'une manière spéciale. Pour ce faire, à la fin de la séquence de chiffres hexadécimaux qui composent un nombre hexadécimal, écrivez la lettre latine " h”. C'est une condition préalable. Si un nombre hexadécimal commence par une lettre, alors un zéro non significatif est écrit devant : 0 ef15 h.

Presque chaque phrase contient une description de l'objet sur lequel ou à l'aide duquel une action est effectuée. Ces objets sont appelés opérandes... Ils peuvent être définis comme ceci : opérandes- ce sont des objets (des valeurs, des registres ou des cellules mémoire) sur lesquels agissent des instructions ou des directives, ou ce sont des objets qui définissent ou clarifient l'action d'instructions ou de directives.

Il est possible d'effectuer la classification suivante des opérandes :

­ opérandes constants ou immédiats;

­ opérandes d'adresse;

­ opérandes mobiles;

compteur d'adresses;

­ enregistrer l'opérande ;

­ opérandes de base et d'index ;

­ opérandes structurels;

enregistrements.

Les opérandes sont des composants élémentaires à partir desquels est formée une partie d'une instruction machine, désignant les objets sur lesquels une opération est effectuée. Dans un cas plus général, les opérandes peuvent être inclus en tant que composants dans des formations plus complexes, appelées expressions.

Expressions sont des combinaisons d'opérandes et d'opérateurs, traités comme un tout. Le résultat de l'évaluation d'une expression peut être une adresse d'une cellule de mémoire ou une valeur constante (absolue).

­ 3 types d'instructions assembleur

Listons les types possibles opérateurs assembleurs et des règles syntaxiques pour la formation d'expressions assembleur :

­ opérateurs arithmétiques;

­ opérateurs postés;

­ opérateurs de comparaison ;

­ Opérateurs logiques;

­ opérateur d'indexation ;

­ opérateur de remplacement de type ;

­ opérateur de redéfinition de segment ;

­ opérateur de nommage du type de structure ;

­ opérateur pour obtenir le composant de segment de l'adresse d'expression ;

­ opérateur pour obtenir le décalage d'une expression.

1 Directives assembleur

­ Les directives de l'assembleur sont :

1) Directives de segmentation. Au cours de la discussion précédente, nous avons découvert toutes les règles de base pour écrire des commandes et des opérandes dans un programme assembleur. La question de savoir comment formuler correctement la séquence de commandes pour que le traducteur puisse les traiter et que le microprocesseur puisse les exécuter reste ouverte.

En considérant l'architecture du microprocesseur, nous avons appris qu'il dispose de six registres de segments, à travers lesquels il peut fonctionner simultanément :

­ avec un segment de code ;

­ avec un segment de pile ;

­ avec un segment de données ;

­ avec trois segments de données supplémentaires.

Physiquement, un segment est une zone mémoire occupée par des instructions et (ou) des données, dont les adresses sont calculées par rapport à la valeur dans le registre de segment correspondant. La description syntaxique d'un segment en assembleur est la construction illustrée à la figure 13 :


­ Figure 13 - Description syntaxique d'un segment en assembleur

Il est important de noter que la fonctionnalité d'un segment est un peu plus large que la simple division d'un programme en blocs de code, de données et de pile. La segmentation fait partie d'un mécanisme plus général lié à le concept de programmation modulaire. Il suppose l'unification de la conception des modules objets créés par le compilateur, y compris ceux issus des différents langages de programmation. Cela vous permet de combiner des programmes écrits dans différentes langues. Les opérandes de la directive SEGMENT sont destinés à implémenter diverses variantes d'une telle union.

2) Directives de gestion des listes. Les directives de contrôle de liste sont réparties dans les groupes suivants :

­ directives générales de contrôle des inscriptions;

­ directives pour la sortie vers la liste des fichiers inclus ;

­ directives pour la sortie des blocs d'assemblage conditionnels ;

­ directives pour lister les macros ;

­ des directives pour la sortie d'informations sur les références croisées à la liste ;

­ directives pour changer le format de la liste.

2 Jeu d'instructions du processeur

Le jeu d'instructions du processeur est illustré à la figure 14.

Considérons les principaux groupes de commandes.

­ Figure 14 - Classement des instructions assembleur

Les équipes sont :

1 Commandes de transfert de données. Ces commandes occupent une place très importante dans le jeu d'instructions de tout processeur. Ils remplissent les fonctions essentielles suivantes :

­ stocker le contenu des registres internes du processeur en mémoire ;

­ copier du contenu d'une zone de mémoire à une autre ;

­ écriture sur les périphériques E/S et lecture depuis les périphériques E/S.

Sur certains processeurs, toutes ces fonctions sont exécutées par une seule commande. mov (pour les transferts d'octets - MOVB ) mais avec différentes méthodes d'adressage des opérandes.

Sur d'autres processeurs en plus de la commande mov il existe plusieurs autres commandes pour exécuter les fonctions répertoriées. De plus, les commandes de transfert de données incluent les commandes d'échange d'informations (leur désignation est basée sur le motÉchange ). L'échange d'informations entre registres internes, entre deux moitiés d'un registre (ÉCHANGER ) ou entre un registre et un emplacement mémoire.

2 Commandes arithmétiques. Les instructions arithmétiques traitent les codes d'opérandes comme des codes numériques binaires ou binaires décimaux. Ces commandes peuvent être divisées en cinq groupes principaux :

­ commandes d'opérations à virgule fixe (addition, soustraction, multiplication, division);

­ commandes à virgule flottante (addition, soustraction, multiplication, division);

­ commandes de nettoyage ;

­ commandes d'incrémentation et de décrémentation ;

­ commande de comparaison.

3 Les commandes pour les opérations à virgule fixe opèrent sur des codes dans les registres du processeur ou en mémoire comme des codes binaires normaux. Les instructions à virgule flottante (point) utilisent le format de représentation des nombres avec ordre et mantisse (généralement ces nombres occupent deux emplacements de mémoire consécutifs). Dans les processeurs puissants modernes, l'ensemble d'instructions à virgule flottante ne se limite pas à quatre opérations arithmétiques, mais contient également de nombreuses autres instructions plus complexes, par exemple le calcul de fonctions trigonométriques, de fonctions logarithmiques, ainsi que de fonctions complexes nécessaires au traitement du son. et images.

4 Les instructions d'effacement sont conçues pour écrire un code zéro dans un registre ou une cellule de mémoire. Ces commandes peuvent être remplacées par des commandes de transfert zéro, mais les commandes d'effacement spéciales sont généralement plus rapides que les commandes de transfert.

5 commandes pour incrémenter (augmenter de un) et décrémenter

(décréments de un) sont également très pratiques. Ils peuvent en principe être remplacés par l'addition avec une ou la soustraction d'une commande, mais l'incrémentation et la décrémentation sont plus rapides que l'addition et la soustraction. Ces instructions nécessitent un opérande d'entrée, qui est également un opérande de sortie.

6 L'instruction de comparaison compare deux opérandes d'entrée. En fait, il calcule la différence entre ces deux opérandes, mais ne forme pas un opérande de sortie, mais modifie uniquement les bits dans le registre d'état du processeur en fonction du résultat de cette soustraction. L'instruction suivante après l'instruction de comparaison (généralement une instruction de branchement) analysera les bits dans le registre d'état du processeur et effectuera des actions en fonction de leurs valeurs. Certains processeurs fournissent des instructions pour connecter en guirlande deux séquences d'opérandes en mémoire.

7 Commandes logiques. Les instructions logiques effectuent des opérations logiques (au niveau du bit) sur les opérandes, c'est-à-dire qu'elles considèrent les codes d'opérande non pas comme un nombre unique, mais comme un ensemble de bits séparés. C'est en quoi elles diffèrent des commandes arithmétiques. Les commandes logiques effectuent les opérations de base suivantes :

­ ET logique, OU logique, addition modulo 2 (OU exclusif) ;

­ décalages logiques, arithmétiques et cycliques;

­ vérifier les bits et les opérandes ;

­ mise à 1 et effacement des bits (drapeaux) du registre d'état du processeur ( PSW).

Les instructions logiques vous permettent de calculer des fonctions logiques de base à partir de deux opérandes d'entrée bit par bit. De plus, l'opération AND est utilisée pour forcer l'effacement des bits spécifiés (un code de masque est utilisé comme l'un des opérandes, dans lequel les bits à effacer sont mis à zéro). L'opération OU est utilisée pour forcer les bits spécifiés (comme l'un des opérandes, un code de masque est utilisé, dans lequel les bits nécessitant une mise à un sont égaux à un). L'opération "OU exclusif" est utilisée pour inverser les bits spécifiés (un code de masque est utilisé comme l'un des opérandes, dans lequel les bits à inverser sont mis à un). Les instructions nécessitent deux opérandes d'entrée et forment un opérande de sortie.

8 Les commandes Shift permettent de décaler le code de l'opérande bit à bit vers la droite (vers les bits de poids faible) ou vers la gauche (vers les bits de poids fort). Le type de décalage (logique, arithmétique ou cyclique) détermine quelle sera la nouvelle valeur du bit le plus significatif (lors du décalage vers la droite) ou du bit le moins significatif (lors du décalage vers la gauche) et détermine également si la valeur précédente du bit le plus significatif (lors du décalage vers la gauche) sera enregistré quelque part ou le bit le moins significatif (lors du décalage vers la droite). Les décalages cycliques permettent aux bits d'un opérande d'être décalés de manière circulaire (dans le sens des aiguilles d'une montre lorsqu'ils sont décalés vers la droite, ou dans le sens antihoraire lorsqu'ils sont décalés vers la gauche). Dans ce cas, le drapeau de retenue peut ou non être inclus dans la bague de changement de vitesse. Le bit d'indicateur de retenue (s'il est utilisé) stocke la valeur du bit le plus significatif lorsqu'il est cyclé vers la gauche et du bit le moins significatif lorsqu'il est cyclé vers la droite. En conséquence, la valeur du bit d'indicateur de retenue sera écrasée dans le bit le moins significatif lors d'un cycle vers la gauche et dans le bit le plus significatif lors d'un cycle vers la droite.

9 Commandes de transitions. Les instructions de saut sont conçues pour organiser toutes sortes de boucles, de branches, d'appels de sous-programmes, etc., c'est-à-dire qu'elles perturbent le flux séquentiel du programme. Ces commandes écrivent une nouvelle valeur dans le registre du compteur de commandes et font ainsi sauter le processeur non pas à la commande suivante dans l'ordre, mais à toute autre commande de la mémoire programme. Certaines commandes de transition fournissent un retour supplémentaire au point à partir duquel la transition a été effectuée, d'autres ne le permettent pas. Si return est fourni, les paramètres actuels du processeur sont enregistrés sur la pile. Si aucun retour n'est fourni, les paramètres actuels du processeur ne sont pas enregistrés.

Les commandes de transition sans retour en arrière sont divisées en deux groupes :

­ commandes de saut inconditionnel;

­ commandes de saut conditionnel.

Ces commandes utilisent les mots Branchez et sautez.

Les instructions de saut inconditionnel provoquent un saut vers une nouvelle adresse indépendamment de tout. Ils peuvent provoquer un saut d'une quantité spécifiée de décalage (en avant ou en arrière) ou vers une adresse mémoire spécifiée. La valeur de décalage ou la nouvelle valeur d'adresse est spécifiée comme opérande d'entrée.

Les instructions de saut conditionnel ne provoquent pas toujours un saut, mais uniquement lorsque les conditions spécifiées sont remplies. Ces conditions sont généralement les valeurs des drapeaux dans le registre d'état du processeur ( PSW ). C'est-à-dire que la condition de transition est le résultat de l'opération précédente qui modifie les valeurs des drapeaux. Il peut y avoir de 4 à 16 de telles conditions de saut au total. Plusieurs exemples de commandes de saut conditionnel :

­ transition si égale à zéro ;

­ transition s'il n'est pas égal à zéro ;

­ sauter s'il y a débordement;

­ sauter s'il n'y a pas de débordement ;

­ transition si supérieure à zéro ;

­ sauter si inférieur ou égal à zéro.

Si la condition de transition est remplie, la nouvelle valeur est chargée dans le registre de commande. Si la condition de saut n'est pas remplie, le compteur d'instructions est simplement incrémenté et le processeur sélectionne et exécute l'instruction suivante dans l'ordre.

La commande de comparaison (CMP) précédant la commande de branchement conditionnel (voire plusieurs commandes de branchement conditionnel) est utilisée spécifiquement pour vérifier les conditions de saut. Mais les drapeaux peuvent être définis par n'importe quelle autre commande, par exemple, une commande de transfert de données, n'importe quelle commande arithmétique ou logique. Notez que les commandes de saut elles-mêmes ne changent pas les drapeaux, ce qui vous permet simplement de mettre plusieurs commandes de saut les unes après les autres.

Les commandes d'interruption occupent une place particulière parmi les commandes de retour en arrière. Ces instructions nécessitent un numéro d'interruption (adresse vectorielle) comme opérande d'entrée.

Production:

Le langage assembleur est une représentation symbolique d'un langage machine. Le langage d'assemblage pour chaque type d'ordinateur est différent. Un programme en langage assembleur est un ensemble de blocs de mémoire appelés segments de mémoire. Chaque segment contient un ensemble de phrases de langage, dont chacune occupe une ligne distincte de code de programme. Les phrases d'assemblage sont de quatre types : commandes ou instructions, macros, directives, lignes de commentaires.

Toutes les lettres latines sont des caractères valides lors de l'écriture du texte du programme : A-Z,a-z... Dans ce cas, les lettres majuscules et minuscules sont considérées comme équivalentes ; chiffres de 0 avant que 9 ; panneaux ? , @ , $ , _ , & ; séparateurs , . () < > { } + / * % ! " " ? = # ^ .

Les types suivants d'instructions d'assembleur et de règles syntaxiques pour la formation d'expressions d'assembleur s'appliquent. opérateurs arithmétiques, opérateurs de décalage, opérateurs de comparaison, opérateurs logiques, opérateur d'index, opérateur de substitution de type, opérateur de substitution de segment, opérateur de dénomination de type de structure, opérateur pour obtenir le composant de segment d'une adresse d'expression, opérateur pour obtenir le décalage d'une expression.

Le système de commandement est divisé en 8 groupes principaux.

­ Questions de contrôle :

1 Qu'est-ce que le langage assembleur ?

2 Quels symboles peuvent être utilisés pour écrire des commandes en langage assembleur ?

3 Que sont les labels et à quoi servent-ils ?

4 Expliquer la structure des commandes assembleur.

5 Citez 4 types de phrases en assembleur.

Assembleur Structures

Les tableaux que nous avons considérés ci-dessus sont une collection d'éléments du même type. Mais souvent dans les applications, il devient nécessaire de considérer une certaine collection de données de différents types comme un certain type unique.

Ceci est très important, par exemple, pour les programmes de base de données, où il est nécessaire d'associer une collection de données de différents types à un seul objet.

Par exemple, nous avons examiné le Listing 4 plus tôt, dans lequel nous avons travaillé avec un tableau d'éléments de trois octets. Chaque élément, à son tour, représentait deux éléments de types différents : un champ de compteur d'un octet et un champ de deux octets qui pouvait transporter d'autres informations nécessaires au stockage et au traitement. Si le lecteur est familier avec l'un des langages de haut niveau, alors il sait qu'un tel objet est généralement décrit à l'aide d'un type de données spécial - structure.

Afin d'améliorer la convivialité du langage assembleur, ce type de données y a également été introduit.

Un prieuré structure est un type de données composé d'un nombre fixe d'éléments de types différents.

Pour utiliser des structures dans un programme, vous devez faire trois choses :

    Interroger modèle de structure .

    Par définition, cela signifie définir un nouveau type de données, qui peut ensuite être utilisé pour définir des variables de ce type.

    Définir instance de structure .

    Cette étape implique l'initialisation d'une variable spécifique avec une structure prédéfinie (à l'aide d'un modèle).

    Organiser accès aux éléments de structure .

Il est très important que vous compreniez dès le départ quelle est la différence entre la description structure dans le programme et ses définir.

Décris la structure dans le programme signifie uniquement pour indiquer son schéma ou son modèle ; aucune mémoire n'est allouée.

Ce modèle ne peut être considéré que comme une information pour le traducteur sur l'emplacement des champs et leurs valeurs par défaut.

Définir structure signifie demander au traducteur d'allouer de la mémoire et d'attribuer un nom symbolique à cette zone mémoire.

Vous ne pouvez décrire la structure d'un programme qu'une seule fois, mais vous pouvez la définir autant de fois que vous le souhaitez.

Description du modèle de structure

La description du modèle de structure a la syntaxe suivante :

nom_structure STRUC

struct_name FIN

Ici est une séquence de directives décrivant des données db, dw, dd, dq et dt.

Leurs opérandes déterminent la taille des champs et, le cas échéant, les valeurs initiales. Ces valeurs seront probablement initialisées aux champs correspondants lors de la définition de la structure.

Comme nous l'avons noté lors de la description du modèle, aucune mémoire n'est allouée, car ce n'est qu'une information pour le traducteur.

Emplacement Le modèle dans le programme peut être arbitraire, mais, suivant la logique du traducteur à une passe, il doit être situé jusqu'à l'endroit où la variable avec le type de cette structure est définie. C'est-à-dire que lors de la description d'une variable avec le type d'une certaine structure dans un segment de données, son modèle doit être placé au début du segment de données ou avant celui-ci.

Envisageons de travailler avec des structures en utilisant l'exemple de la modélisation d'une base de données d'employés d'un certain département.

Pour simplifier, afin de s'affranchir des problèmes de conversion des informations lors de la saisie, on conviendra que tous les champs sont symboliques.

Définissons la structure d'enregistrement de cette base de données avec le modèle suivant :

Définir des données avec un type de structure

Pour utiliser la structure décrite à l'aide du modèle dans le programme, vous devez définir une variable avec le type de cette structure. Pour cela, la construction syntaxique suivante est utilisée :

[nom de la variable] nom_structure

    Nom de variable- identifiant d'une variable de ce type structurel.

    Le nom de la variable est facultatif. Si vous ne le précisez pas, une zone mémoire de la taille de la somme des longueurs de tous les éléments de la structure sera simplement allouée.

    liste de valeurs- une liste séparée par des virgules des valeurs initiales des éléments de structure, entre crochets angulaires.

    Son affectation est également facultative.

    Si la liste est incomplète, tous les champs de structure de cette variable sont initialisés avec les valeurs du modèle, le cas échéant.

    Il est permis d'initialiser des champs individuels, mais dans ce cas, les champs manquants doivent être séparés par des virgules. Les champs manquants seront initialisés avec les valeurs du modèle de structure. Si, lors de la définition d'une nouvelle variable avec le type de cette structure, nous sommes d'accord avec toutes les valeurs des champs de son modèle (c'est-à-dire définis par défaut), il vous suffit d'écrire des chevrons.

    Par exemple: travailleur victorieux.

Par exemple, définissons plusieurs variables avec le type de structure décrit ci-dessus.

Méthodes pour travailler avec la structure

L'idée d'introduire un type structuré dans n'importe quel langage de programmation est de combiner des variables de types différents en un seul objet.

Le langage doit disposer d'un moyen d'accéder à ces variables dans une instance spécifique de la structure. Afin de faire référence à un champ d'une certaine structure dans une commande, un opérateur spécial est utilisé - symbole ". " (point)... Il est utilisé dans la syntaxe suivante :

    expression_adresse- l'identifiant d'une variable d'un certain type structurel ou d'une expression entre parenthèses selon les règles syntaxiques indiquées ci-dessous (Fig. 1) ;

    nom_champ_structure- le nom du champ du modèle de structure.

    Ceci, en fait, est aussi une adresse, ou plutôt, le décalage du champ depuis le début de la structure.

Ainsi, l'opérateur " . "(point) évalue l'expression

Figure. cinq. La syntaxe d'une expression d'adresse dans un opérateur d'accès à un champ de structure

Démontrons en utilisant l'exemple de la structure que nous avons définie ouvrier quelques techniques pour travailler avec des structures.

Par exemple, extraire dans hache valeurs de champ avec l'âge. Puisqu'il est peu probable que l'âge d'une personne valide soit supérieur à 99 ans, alors après avoir placé le contenu de ce champ de caractère dans le registre hache il sera pratique de le convertir en représentation binaire avec la commande annonce.

Attention, en raison du principe de stockage des données "Octet le moins significatif au moins l'adresse significative" le chiffre d'âge le plus élevé sera placé dans Al, et le plus jeune - en euh.

Pour régler, il suffit d'utiliser la commande xchg al, ah:

mov hache, mot ptr sotr1.age; dans al age sotr1

ou tu peux faire ça :

Le travail ultérieur avec un tableau de structures est effectué de la même manière qu'avec un tableau unidimensionnel. Plusieurs questions se posent ici :

Qu'en est-il de la taille et comment organiser l'indexation des éléments du tableau ?

Comme pour les autres identifiants définis dans le programme, le traducteur affecte le nom du type de structure et le nom de la variable avec le type de structure à l'attribut type. La valeur de cet attribut est la taille en octets occupée par les champs de cette structure. Vous pouvez récupérer cette valeur à l'aide de l'opérateur taper.

Une fois que la taille d'une instance de structure est connue, il n'est pas difficile d'organiser l'indexation dans un tableau de structures.

Par exemple:

Comment copier un champ d'une structure vers le champ correspondant d'une autre structure ? Ou comment copier toute la structure ? copions le champ nom troisième employé sur le terrain nom cinquième employé :

mas_sotr travailleur 10 dup ()

mov bx, décalage mas_sotr

mov si, (type travailleur) * 2 ; si = 77 * 2

mov di, (type travailleur) * 4 ; si = 77 * 4

Il me semble que le métier de programmeur, tôt ou tard, fait ressembler une personne à une bonne femme au foyer. Lui, comme elle, est constamment à la recherche d'où économiser quelque chose, réduire et faire un merveilleux dîner à partir d'un minimum de produits. Et si cela réussit, alors la satisfaction morale n'est pas moins, et peut-être plus, que d'un merveilleux dîner avec une femme au foyer. Le degré de cette satisfaction, me semble-t-il, dépend du degré d'amour pour votre métier.

D'autre part, les succès dans le développement de logiciels et de matériel détendent quelque peu le programmeur, et assez souvent une situation similaire au proverbe bien connu sur une mouche et un éléphant est observée - pour résoudre un petit problème, des moyens lourds sont utilisés, dont l'efficacité, dans le cas général, n'est significative que lors de la mise en œuvre de projets relativement importants.

La présence des deux types de données suivants dans la langue s'explique probablement par la volonté de "l'hôtesse" d'utiliser le plus efficacement possible la zone de travail de la table (RAM) lors de la préparation des aliments ou pour le placement des produits (données du programme ).

Commandes d'assembleur (conférence)

PLAN DE CONFÉRENCE

1. Les principaux groupes d'opérations.

Pentium.

1. Groupes d'opérations de base

Les microprocesseurs exécutent un ensemble d'instructions qui implémentent les groupes d'opérations de base suivants :

Opérations d'expédition,

Opérations arithmétiques,

Opérations logiques,

Opérations de décalage,

Opérations de comparaison et de test,

Opérations sur les bits,

Opérations de contrôle de programme ;

Opérations de contrôle du processeur.

2. Mnémocodes des commandes du processeur Pentium

Lors de la description des commandes, leurs symboles mnémoniques (codes mnémoniques) sont généralement utilisés, qui sont utilisés pour définir la commande lors de la programmation en langage assembleur. Pour différentes versions d'Assembler, les codes mnémoniques de certaines commandes peuvent différer. Par exemple, pour une commande d'appel d'un sous-programme, le code mnémonique est utiliséAPPEL ou alors JSR ("Sauter à Sous-routine»). Cependant, les codes mnémoniques de la plupart des commandes pour les principaux types de microprocesseurs coïncident ou diffèrent légèrement, car ce sont des abréviations des mots anglais correspondants qui déterminent l'opération en cours. Considérez les codes mnémoniques des commandes adoptés pour les processeurs Pentium.

Transférer des commandes. L'équipe principale de ce groupe est l'équipemov , qui assure le transfert de données entre deux registres ou entre un registre et une cellule mémoire. Certains microprocesseurs mettent en œuvre le transfert entre deux cellules mémoire, ainsi que le transfert en masse du contenu de plusieurs registres depuis la mémoire. Par exemple, les microprocesseurs de la famille 68 xxx de Motorola exécuter la commandeBOUGE TOI , assurant le transfert d'une cellule mémoire à une autre, et la commandeMOVEM , qui écrit en mémoire ou charge depuis la mémoire le contenu d'un ensemble donné de registres (jusqu'à 16 registres). ÉquipeXCHG effectue l'échange mutuel du contenu de deux registres du processeur ou d'un registre et d'une cellule mémoire.

Commandes d'entrée DANS et retrait EN DEHORS transférer des données du registre du processeur vers un périphérique externe ou recevoir des données d'un périphérique externe vers un registre. Ces commandes spécifient le numéro du périphérique d'interface (port I/O) à travers lequel les données sont transférées. Notez que de nombreux microprocesseurs n'ont pas de commandes spéciales pour accéder aux périphériques externes. Dans ce cas, l'entrée et la sortie des données dans le système sont effectuées à l'aide de la commandemov , dans laquelle l'adresse du périphérique d'interface requis est définie. Ainsi, le dispositif externe est adressé en tant que cellule mémoire, et une certaine section est allouée dans l'espace d'adressage, dans lequel se trouvent les adresses des dispositifs d'interface (ports) connectés au système.

Commandes arithmétiques. Les commandes principales de ce groupe sont les commandes d'addition, de soustraction, de multiplication et de division, qui ont un certain nombre d'options. Commandes d'ajout AJOUTER et soustraction SOUS effectuer les opérations appropriées aveccobsédé par deux registres, un registre et un emplacement mémoire, ou utilisant un opérande immédiat. Commandes UN D C , SB B l'addition et la soustraction sont effectuées en tenant compte de la valeur de l'attributC, qui est défini lorsque le transfert est formé lors de l'exécution de l'opération précédente. A l'aide de ces commandes, on réalise l'addition séquentielle des opérandes dont le nombre de bits dépasse la capacité du processeur. Équipe NEG change le signe de l'opérande, le traduisant en un code complémentaire.

Les opérations de multiplication et de division peuvent être effectuées sur des nombres signés (commandesje MUL, je DIV ) ou non signé (commandes MUL, DIV L'un des opérandes est toujours alloué dans un registre, le second peut être dans un registre, un emplacement mémoire ou un opérande direct. Le résultat de l'opération se trouve dans le registre. Lors de la multiplication (commandesMUL , IMUL ), le résultat est un résultat à deux chiffres, pour lequel deux registres sont utilisés. Lors de la division (commandesDIV , IDIV ) comme dividende, un opérande à deux chiffres est utilisé, situé dans deux registres, et par conséquent, le quotient et le reste sont écrits dans deux registres.

Commandes booléennes ... Presque tous les microprocesseurs effectuent des opérations logiques ET, OU, OU exclusif, qui sont effectuées sur les mêmes bits des opérandes à l'aide de commandes ET, OU, X OU ALORS ... Les opérations sont effectuées sur le contenu de deux registres, un registre et un emplacement mémoire, ou à l'aide d'un opérande immédiat. Équipe NE PAS inverse la valeur de chaque bit de l'opérande.

Commandes de décalage... Les microprocesseurs effectuent des décalages arithmétiques, logiques et cycliques des opérandes adressés d'un ou plusieurs bits. L'opérande décalé peut se trouver dans un registre ou un emplacement mémoire, et le nombre de bits de décalage est spécifié à l'aide de l'opérande immédiat contenu dans l'instruction, ou est déterminé par le contenu du registre spécifié. La fonction de transfert est généralement impliquée dans la mise en œuvre du décalage.Cdans le registre d'état (RS ou alors FLAG), dans lequel se trouve le dernier bit de l'opérande, qui est retiré du registre ou de la cellule mémoire.

Comparer et tester les équipes ... La comparaison des opérandes se fait généralement à l'aide de la commandeCMP , qui soustrait les opérandes en fixant les valeurs caractéristiques N, Z, V, C dans le registre d'état en fonction du résultat. Dans ce cas, le résultat de la soustraction n'est pas enregistré et les valeurs des opérandes ne sont pas modifiées. Une analyse ultérieure des valeurs de caractéristiques obtenues permet de déterminer la valeur relative (>,<, =) операндов со знаком или без знака. Использование различных способов адресации позволяет производит сравнение содержимого двух регистров, регистра и ячейки памяти, непосредственно заданного операнда с содержимым регистра или ячейки памяти.

Certains microprocesseurs exécutent une commande de test TST , qui est une variante à opérande unique de la commande de comparaison. Lorsque cette commande est exécutée, les signes sont mis N, Z selon le signe et la valeur (égale ou non à zéro) de l'opérande adressé.

Commandes d'opérations sur les bits ... Ces commandes fixent la valeur de la caractéristiqueCdans le registre d'état en fonction de la valeur du bit testémilliards dans l'opérande adressé. Dans certains microprocesseurs, selon le résultat du test du bit, le signe est définiZ... Numéro de bit de testmest fixé soit par le contenu du registre spécifié dans la commande, soit par un opérande immédiat.

Les commandes de ce groupe implémentent différentes options pour changer le bit testé. BT conserve la valeur de ce bit inchangée. B T S après le test définit la valeur milliards= 1, et la commande B T C - valeur milliards= 0 commande B T C inverse la valeur du bit bn après l'avoir testé.

Opérations de contrôle de programme. Un grand nombre de commandes sont utilisées pour contrôler le programme, parmi lesquelles :

- commandes de transfert de contrôle inconditionnelles ;

- commandes de saut conditionnel ;

- des équipes pour l'organisation des cycles de programmes ;

- commandes d'interruption ;

- commandes pour modifier les fonctionnalités.

Le transfert inconditionnel du contrôle est effectué par la commandeJMP qui se charge dans le compteur de programmeordinateurnouveau contenu, qui est l'adresse de la prochaine commande à exécuter. Cette adresse est soit directement spécifiée dans la commandeJMP (adressage direct), ou calculé comme la somme du contenu actuelordinateuret l'offset de commande, qui est un nombre signé (adressage relatif). Commeordinateurcontient l'adresse de la prochaine commande de programme, la dernière méthode définit l'adresse de saut, décalée de l'adresse suivante d'un nombre spécifié d'octets. Avec un décalage positif, la transition vers les commandes de programme suivantes, avec un décalage négatif - vers les précédentes.

Un appel de sous-programme est également effectué par transfert de contrôle inconditionnel à l'aide de la commandeAPPEL (ou alors JSR ). Cependant, dans ce cas, avant de charger dansordinateur nouveau contenu qui fixe l'adresse de la première commande du sous-programme, il est nécessaire de sauvegarder sa valeur courante (l'adresse de la prochaine commande) afin d'assurer un retour au programme principal (ou au sous-programme précédent lors de l'imbrication de sous-programmes) après l'exécution du sous-programme. Les commandes de branchement conditionnel (branches de programme) sont chargées dansordinateurnouveau contenu si certaines conditions sont remplies, qui sont généralement fixées en fonction de la valeur actuelle de divers signes dans le registre d'état. Si la condition n'est pas remplie, la commande de programme suivante est exécutée.

Les commandes de gestion des fonctionnalités permettent l'écriture - la lecture du contenu du registre d'état, qui stocke les fonctionnalités, ainsi que la modification des valeurs des fonctionnalités individuelles. Par exemple, dans les processeurs Pentium, les commandes sont implémentées LAHF et SAHF qui chargent l'octet de poids faible contenant les signes du registre d'état FLAGà l'octet de poids faible du registre EAX et en remplissant l'octet de poids faible FLAG du registre E AX.. Équipes CLC, STC effectuer le paramétrage des valeurs de l'attribut de transfert CF = 0, CF = 1, et la commande CMC provoque l'inversion de la valeur de cet attribut.Étant donné que les caractéristiques déterminent le déroulement de l'exécution du programme pendant les sauts conditionnels, les commandes de modification des caractéristiques sont généralement utilisées pour contrôler le programme.

Commandes CPU ... Ce groupe comprend les commandes d'arrêt, aucune opération et un certain nombre de commandes qui déterminent le mode de fonctionnement du processeur ou de ses blocs individuels. ÉquipeHLT termine l'exécution du programme et met le processeur dans un état d'arrêt, dont la sortie se produit lorsqu'un signal d'interruption ou de redémarrage est reçu ( Réinitialiser). Équipe NON (commande "Vide"), qui ne provoque l'exécution d'aucune opération, permet de mettre en oeuvre des retards de programme ou de combler les lacunes formées dans le programme.

Commandes spéciales CLI, IST désactiver et activer le service des demandes d'interruption. Dans les processeurs Pentium le bit de contrôle (drapeau) est utilisé pour celaSI dans le registre FLAG.

De nombreux microprocesseurs modernes exécutent une commande d'identification qui permet à un utilisateur ou à un autre dispositif d'obtenir des informations sur le type de processeur utilisé dans un système donné. Dans les processeurs Pentuim la commande est pour ça ID CPU , lors de l'exécution, les données nécessaires sur le processeur vont aux registres EAX,EBX,ECX,EDX et peut ensuite être lu par l'utilisateur ou le système d'exploitation.

En fonction des modes de fonctionnement mis en œuvre par le processeur et des types de données spécifiés en cours de traitement, l'ensemble des commandes exécutables peut être considérablement étendu.

Certains processeurs effectuent des opérations arithmétiques sur des nombres décimaux binaires ou exécutent des commandes spéciales pour corriger le résultat lors du traitement de tels nombres. De nombreux processeurs hautes performances incluent FPU - unité de traitement des numéros c Point flottant.

Un certain nombre de processeurs modernes implémentent le traitement de groupe de plusieurs entiers ou nombres c Virgule flottante avec une seule instruction selon le principe SIMD (« Instruction unique - Données multiples ”) -“ Une commande - Beaucoup de données ”. L'exécution simultanée d'opérations sur plusieurs opérandes améliore considérablement les performances du processeur lorsque vous travaillez avec des données vidéo et audio. De telles opérations sont largement utilisées pour le traitement d'images, les signaux audio et d'autres applications. Pour effectuer ces opérations, des blocs spéciaux ont été introduits dans les processeurs qui implémentent les ensembles d'instructions correspondants, qui dans divers types de processeurs ( Pentium, Athlon) ont été nommésMMX (“ Milti- Extension média ”) - Extension Multimédia,ESS(“Streaming SIMD Extension”) - Streaming SIMD - prolongement, “3 Extension- Extension 3D.

Une caractéristique des processeurs de l'entreprise Intelligence , à partir du modèle 80286, un contrôle prioritaire lors de l'accès à la mémoire est fourni, ce qui est assuré lorsque le processeur fonctionne en mode d'adresse virtuelle protégée - " Mode protégé "(Mode protégé). Pour mettre en œuvre ce mode, des groupes spéciaux de commandes sont utilisés, qui servent à organiser la protection de la mémoire conformément à l'algorithme d'accès prioritaire adopté.

Structure des instructions en langage assembleur La programmation au niveau des instructions machine est le niveau minimum auquel la programmation informatique est possible. Le jeu d'instructions de la machine doit être suffisant pour effectuer les actions requises en envoyant des instructions au matériel de la machine. Chaque instruction machine se compose de deux parties : une d'exploitation qui définit « que faire » et une opérande qui définit les objets de traitement, c'est-à-dire ce qu'il faut refaire. Une instruction machine à microprocesseur écrite en langage assembleur est une seule ligne de la forme suivante : étiquette instruction/directive opérande(s) ; commentaires L'étiquette, la commande / la directive et l'opérande sont séparés par au moins un espace ou un caractère de tabulation. Les opérandes de commande sont séparés par des virgules.

Structure d'instruction en langage assembleur Une instruction en langage assembleur indique au traducteur quelle action le microprocesseur doit entreprendre. Les directives d'assembleur 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 définit la valeur initiale des données (dans le segment de données) ou les éléments sur lesquels agira la commande (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 de commande. Si une commande ou une directive doit être poursuivie sur la ligne suivante, la barre oblique inverse est utilisée : "". Par défaut, l'assembleur ne fait pas la distinction entre les majuscules et les minuscules lors de l'écriture des commandes et des directives. Exemples de directive et de commande 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é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. La longueur maximale de l'identifiant est de 255 caractères, mais le traducteur accepte les 32 premiers, ignore le reste. Toutes les étiquettes écrites dans une ligne qui ne contient pas de directive d'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 chaîne. Il est recommandé de les noter dans une colonne pour une meilleure lisibilité du programme.

Etiquettes Toutes les étiquettes qui sont écrites dans une ligne qui ne contient pas de directive assembleur doivent se terminer par un deux-points ":". L'étiquette, la commande (directive) et l'opérande ne doivent pas nécessairement commencer à une position particulière dans la chaîne. Il est recommandé de les noter dans une colonne pour une meilleure lisibilité du programme.

Commentaires L'utilisation de commentaires dans un programme améliore la clarté, en particulier lorsque l'intention du jeu d'instructions n'est pas claire. 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. Le commentaire peut contenir n'importe quel caractère imprimable, y compris "espace". Un commentaire peut s'étendre sur toute la ligne ou suivre une commande sur la même ligne.

La structure d'un programme en langage assembleur Un programme écrit en langage assembleur peut être constitué de plusieurs parties, appelées modules, dans chacune desquelles un ou plusieurs segments de données, de pile et de code peuvent être définis. Tout programme en langage assembleur complet doit inclure un module principal, ou principal, à partir duquel son exécution commence. Un module peut contenir des segments de programme, des segments de données et des segments 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. MODÈLE modificateur 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 d'exploitation Code et entrelacement de données PETIT PROCHE MS-DOS Autorisé PETIT PROCHE MS-DOS, Windows Non MOYEN LOIN PROCHE MS-DOS, Windows Non COMPACT NEAR FAR MS-DOS, Windows Non LARGE FAR MS-DOS, Windows Non ÉNORME 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 tous les codes sont situés dans un 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 adressé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, tous les liens dans les segments de code étant considérés comme éloignés par défaut, et les liens dans un segment de données comme proches. Le modèle compact prend en charge plusieurs segments de données utilisant l'adressage de données éloignées et un segment de données 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 de code et de données sont considérées comme distantes. 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 modèle minuscule dans la mesure où les données et le code sont contenus dans un seul segment 32 bits. Développer un programme pour le modèle plat avant la directive. modèle plat l'une des directives doit être placé :. 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 indique 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 modificateur memory_model, call_convention, OS_type, stack_parameter Le paramètre modifier permet de définir les types de segments et peut prendre les valeurs suivantes : use 16 (les segments du modèle sélectionné sont utilisés en 16 bits) use 32 (segments du modèle sélectionné sont utilisés en 32 bits). Le paramètre call_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. MODEL modificateur memory_model, call_ convention, os_type, stack_parameter OS_type est l'OS_DOS par défaut et est actuellement la seule valeur prise en charge pour ce paramètre. Stack_parameter est défini sur : NEARSTACK (le registre SS est 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 « ne rien faire ». 686 P. MODÈLE PLAT, STDCALL. LES DONNÉES. CODE DEBUT : RET FIN DEBUT RET - commande du microprocesseur. Il garantit la bonne fin du programme. Le reste du programme est lié au travail du traducteur. ... 686 P - Commandes en mode protégé Pentium 6 (Pentium II) autorisées. Cette directive sélectionne le jeu d'instructions assembleur pris en charge en spécifiant le modèle de processeur. ... MODÈLE FLAT, stdcall est un modèle à 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 utilisée.

Un exemple de programme « ne rien faire ». 686 P. MODÈLE PLAT, STDCALL. LES DONNÉES. CODE DEBUT : RET FIN DEBUT. DATA est un segment de programme contenant des données. Ce programme n'utilise pas la pile, donc le fichier. PILE est manquant. ... CODE est un segment du programme contenant le code. START est une é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 pour marquer la fin du code source du programme. Toutes les lignes suivant 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 le programme démarre. 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 un moyen technique qui convertit un programme, pré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 des instructions machine, chaque traducteur a son propre ensemble de directives et de macro-outils, qui sont souvent incompatibles avec quoi que ce soit. Les principaux types de traducteurs en langage assembleur : MASM (Microsoft Assembler), TASM (Borland Turbo Assembler), FASM (Flat Assembler) - un assembleur multi-passes gratuit écrit par Tomasz Grishtar (Polonais), NASM (Netwide Assembler) - un assembleur gratuit pour Intel x architecture 86, a été créé par Simon Tatham en collaboration avec Julian Hall et est actuellement développé par une petite équipe de développement sur Source. La forge. rapporter.

Src = "https://present5.com/presentation/-29367016_63610977/image-15.jpg" alt = "(! LANG : Diffusion du programme vers Microsoft Visual Studio 2005 1) Créez un projet en choisissant Fichier-> Nouveau-> 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 = "(! LANG : Diffusion du programme vers 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. asm :

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

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

Traduction de programme dans Microsoft Visual Studio 2005 Vérifiez en cliquant avec le bouton droit sur le bonjour. asm de l'arborescence du projet du 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 = "(! LANG: Diffusion du programme vers Microsoft Visual Studio 2005 6) Compilez le fichier en choisissant Build-> Build hello. Prj."> Трансляция программы в Microsoft Visual Studio 2005 6) Откомпилировать файл, выбрав Build->Build hello. prj. 7) Запустить программу, нажав F 5 или выбрав меню Debug->Start Debugging.!}

Programmation sous Windows OS La programmation sous Windows OS est basée sur l'utilisation de fonctions API (Application Program Interface). Leur nombre atteint 2000. Le programme pour Windows se compose en grande partie de tels appels. Toutes les interactions avec les périphériques externes et les ressources du système d'exploitation se produisent, en règle générale, via de telles fonctions. Le système d'exploitation Windows utilise un modèle de mémoire plate. L'adresse de tout emplacement 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 : dialogue (fenêtre principale - dialogue), structure console ou sans fenêtre, structure classique (fenêtre, filaire).

Appel de fonctions API Windows Dans le fichier d'aide, toute fonction API est représentée par le type nom_fonction (FA 1, FA 2, FA 3) Type - le type de la valeur de retour ; ФАх - 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 - handle vers 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 - le texte dans la légende de la fenêtre, u. Type - le type de la fenêtre, en particulier, vous pouvez définir le nombre de boutons de sortie.

Appel de fonctions API Windows int Message. 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 fait des entiers 32 bits : HWND est un entier 32 bits, LPCTSTR est un pointeur 32 bits vers une chaîne, UINT est un entier 32 bits. Le suffixe « A » est souvent ajouté au nom de la fonction pour passer aux versions plus récentes des fonctions.

Appel de fonctions API Windows int Message. 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 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. La commande assembleur CALL est utilisée pour appeler la fonction. 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. Le premier argument à pousser sur la pile est u. Taper. L'appel à la fonction spécifiée ressemblera à ceci : CALL Message. Boîte. [email protégé]

Appel de fonctions API Windows int Message. Boîte (HWND h. Wnd, LPCTSTR lp. Texte, LPCTSTR lp. Légende, UINT u. Type); Le résultat de l'exécution de toute fonction API est, en règle générale, un entier qui est renvoyé dans le registre EAX. La directive OFFSET est un "décalage de segment" ou, en termes généraux, un "pointeur" vers le début d'une ligne. La directive EQU, comme #define en langage C, définit une constante. La directive EXTERN indique au traducteur que la fonction ou l'identifiant est externe au module donné.

Un exemple du programme "Bonjour tout le monde !" ... 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. [email protégé]: À PROXIMITÉ. CODE START : PUSH MB_OK PUSH OFFSET STR 1 PUSH OFFSET STR 2 PUSH HW CALL Message. Boîte. [email protégé] RET FIN DEBUT

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



Vous avez aimé l'article ? Partagez-le