Article de reference

Code machine

Moniteur de langage machine exécuté sur un microprocesseur W65C816S , affichant le désassemblage du code et les dumps des registres et de la mémoire du processeur En informatiqu...

Moniteur de langage machine exécuté sur un microprocesseur W65C816S , affichant le désassemblage du code et les dumps des registres et de la mémoire du processeur
informatique , le code machine est un ensemble de données encodées et structurées pour contrôler l'unité centrale de traitement (CPU) d' un ordinateur via son interface programmable . Un programme informatique est principalement constitué de séquences d'instructions en code machine. Le code machine est dit natif par rapport à son CPU hôte, car il s'agit du langage que le CPU interprète directement. Certains interpréteurs de logiciels traduisent le langage de programmation qu'ils interprètent en code machine virtuel ( bytecode ) et le traitent avec une machine à code P.

Une instruction en code machine amène le processeur à effectuer une tâche spécifique telle que :

L'architecture d' un jeu d'instructions (ISA) définit l'interface avec un processeur et varie selon les familles de processeurs, comme x86 et ARM . En général, le code machine compatible avec une famille ne l'est pas forcément avec une autre, mais il existe des exceptions. L' architecture VAX prend en charge, en option, le jeu d'instructions PDP-11 . L' architecture IA-64 prend en charge, en option, le jeu d'instructions IA-32 . Enfin, le PowerPC 615 peut traiter nativement les instructions PowerPC et x86.

Traduction du code assembleur en code machine

Le langage assembleur permet une conversion relativement directe d'un code source lisible par l'humain vers du code machine. Le code source en assembleur représente les codes numériques en code machine, sous forme de mnémoniques et d'étiquettes. Par exemple, en assembleur pour un processeur x86 , l' opcode 0x90 de l'architecture x86 est représenté en code machine. Bien qu'il soit possible d'écrire un programme en code machine, cette opération est fastidieuse et sujette aux erreurs. C'est pourquoi les programmes sont généralement écrits en assembleur ou, plus couramment, dans un langage de programmation de haut niveau .NOP

Jeu d'instructions

Une instruction machine encode une opération sous forme d'un motif de bits basé sur le format spécifié pour le jeu d'instructions de la machine.

Les jeux d'instructions diffèrent de plusieurs manières. Les instructions d'un même jeu peuvent avoir toutes la même longueur ou des instructions différentes peuvent avoir des longueurs différentes ; elles peuvent être plus petites, de même taille ou plus grandes que la taille des mots de l'architecture. Le nombre d'instructions peut être relativement faible ou élevé. Les instructions peuvent être alignées ou non sur des limites de mémoire particulières, telles que la limite de mot de l'architecture.

Un jeu d'instructions est nécessaire pour exécuter les circuits de la couche logique numérique d'un ordinateur . À ce niveau, le programme doit contrôler les registres, le bus, la mémoire, l'unité arithmétique et logique (UAL) et les autres composants matériels de l'ordinateur. Pour contrôler les caractéristiques architecturales d'un ordinateur , des instructions machine sont créées. Exemples de caractéristiques contrôlées par des instructions machine :

Les critères relatifs aux formats d'enseignement comprennent :

  • Les instructions les plus fréquemment utilisées devraient être plus courtes que les instructions rarement utilisées.
  • Le débit de transfert de mémoire du matériel sous-jacent détermine la flexibilité des instructions d'accès à la mémoire.
  • Le nombre de bits dans le champ d'adresse nécessite une attention particulière.

Le choix de la taille du champ d'adresse implique un compromis entre espace mémoire et vitesse. Sur certains ordinateurs, le nombre de bits du champ d'adresse peut être insuffisant pour accéder à l'intégralité de la mémoire physique. Il convient également de tenir compte de l'espace d'adressage virtuel . Une autre contrainte peut être la limitation de la taille des registres utilisés pour construire l'adresse. Si un champ d'adresse plus court permet une exécution plus rapide des instructions, d'autres propriétés physiques doivent être prises en compte lors de la conception du format d'instruction.

Les instructions peuvent être classées en deux catégories : les instructions à usage général et les instructions à usage spécifique. Les instructions à usage spécifique exploitent des caractéristiques architecturales propres à un ordinateur. Les instructions à usage général contrôlent des caractéristiques architecturales communes à tous les ordinateurs.

Contrôle des instructions à usage général :

  • déplacement de données d'un endroit à un autre
  • Opérations monadiques qui ont un seul opérande pour produire un résultat
  • Opérations dyadiques qui ont deux opérandes pour produire un résultat
  • Comparaisons et sauts conditionnels
  • Appels de procédure
  • Contrôle de boucle
  • Entrée/sortie

Instructions superposées

Sur les architectures de processeurs à jeu d'instructions de longueur variable (comme la famille de processeurs x86 d' Intel ), il est parfois possible, dans les limites du phénomène de resynchronisation du flux de contrôle connu sous le nom de comptage de Kruskal , , par programmation au niveau des opcodes, d'organiser délibérément le code résultant de sorte que deux chemins d'exécution partagent un fragment commun de séquences d'opcodes. On parle alors d'instructions chevauchantes , d'opcodes chevauchants , de code chevauché , de scission d'instruction ou de saut au milieu d'une instruction .

Dans les années 1970 et 1980, le chevauchement des instructions était parfois utilisé pour économiser de l'espace mémoire. On peut citer en exemple l'implémentation des tables d'erreurs dans Altair BASIC de Microsoft , où les instructions entrelacées partageaient leurs octets. Cette technique est rarement employée aujourd'hui, mais peut encore s'avérer nécessaire dans des domaines exigeant une optimisation extrême de la taille au niveau de l'octet, comme lors de l'implémentation des chargeurs d'amorçage qui doivent tenir dans les secteurs d'amorçage .

Elle est parfois utilisée comme technique d'obfuscation de code afin de se prémunir contre le désassemblage et la falsification.

Ce principe est également utilisé dans les séquences de code partagées des binaires volumineux qui doivent s'exécuter sur plusieurs plateformes de processeurs incompatibles en termes de jeu d'instructions.

Cette propriété est également utilisée pour trouver des instructions non intentionnelles appelées gadgets dans les dépôts de code existants et est utilisée dans la programmation orientée retour comme alternative à l'injection de code pour des exploits tels que les attaques de retour à la libc .

Microcode

Sur certains ordinateurs, le code machine de l' architecture est implémenté par une couche sous-jacente encore plus fondamentale appelée microcode , fournissant une interface en langage machine commune à une gamme ou une famille de modèles d'ordinateurs différents, présentant des flux de données sous-jacents très différents . Ceci facilite la portabilité des programmes en langage machine entre différents modèles. La famille d'ordinateurs IBM System/360 et ses successeurs en sont un exemple .

Exemples

IBM 650

Une salle de classe de lycée des années 1960 , avec un tableau de codes d'instructions IBM 650 au-dessus du tableau noir, en haut à droite.
Programme étudiant de 1961 écrit en langage machine IBM 650, basé sur un exercice de manuel scolaire

L' IBM 650 , commercialisé en 1954, était un ordinateur décimal à adressage par mot, dont les instructions et les données étaient stockées sur un tambour magnétique. Chaque mot était composé de dix chiffres suivis du signe plus. Les instructions divisaient les mots en un code d'opération à deux chiffres, une adresse à quatre chiffres du mot de données à traiter et une adresse à quatre chiffres de l'instruction suivante à exécuter. Cette seconde adresse permettait de placer les instructions sur le tambour à proximité de sa position après l'exécution de l'instruction précédente, une pratique appelée optimisation.

Grâce à une table physique de codes d'opération, il était tout à fait possible d'écrire des programmes en code machine. IBM fournissait un formulaire comportant une grille indiquant chaque emplacement mémoire, permettant ainsi au programmeur de suivre les emplacements disponibles. Un format d'instruction unique par carte permettait de charger et d'exécuter directement le programme dans la machine. Plus tard, IBM a introduit un assembleur (SOAP) qui autorisait l'adressage symbolique et effectuait également une première optimisation.

IBM 709x

Les IBM 704, 709, 704x et 709x stockent une instruction dans chaque mot d'instruction ; IBM numérote les bits de gauche à droite comme suit : S, 1, ..., 35. La plupart des instructions ont l'un des deux formats suivants :

Générique
S,1-11
Drapeau 12-13, ignoré dans certaines instructions
14-17 non utilisés
Étiquette 18-20
21-35 ans
Contrôle des registres d'index, autre que TSX
Code d'opération S,1-2
Décrémentation 3-17
Étiquette 18-20
21-35 ans

Pour tous les automates, à l'exception des IBM 7094 et 7094 II, il existe trois registres d'index, désignés A, B et C. L'indexation avec plusieurs bits à 1 dans l'étiquette soustrait le résultat du OU logique des registres d'index sélectionnés, et le chargement avec plusieurs bits à 1 dans l'étiquette charge tous les registres d'index sélectionnés. Les 7094 et 7094 II possèdent sept registres d'index, mais à leur mise sous tension, ils fonctionnent en mode multi-étiquettes . Dans ce mode, ils n'utilisent que trois des registres d'index, de manière compatible avec les machines plus anciennes, et nécessitent une instruction de sortie du mode multi-étiquettes ( LMTM ) pour accéder aux quatre autres.

L'adresse effective est généralement YC(T), où C(T) vaut soit 0 pour une étiquette de 0, soit le OU logique des registres d'index sélectionnés en mode d'étiquettes multiples, soit le registre d'index sélectionné si ce mode n'est pas utilisé. Cependant, l'adresse effective pour les instructions de contrôle des registres d'index est simplement Y.

Un indicateur avec les deux bits à 1 sélectionne l'adressage indirect ; le mot d'adresse indirecte possède à la fois une étiquette et un champ Y.

En plus des instructions de transfert (branchement), ces machines disposent d'instructions de saut qui permettent de sauter conditionnellement un ou deux mots, par exemple, Compare Accumulator with Storage (CAS) effectue une comparaison à trois voies et saute conditionnellement à NSI, NSI+1 ou NSI+2, en fonction du résultat.

MIPS

L' architecture MIPS fournit un exemple précis de code machine dont les instructions sont toujours codées sur 32 bits. Le type général d'instruction est indiqué par le champ op (opération), dont les 6 bits de poids fort sont utilisés. Les instructions de type J (saut) et de type I (immédiat) sont entièrement spécifiées par op . Les instructions de type R (registre) incluent un champ funct (fonction) supplémentaire pour déterminer l'opération exacte. Les champs utilisés pour ces types sont :

Taper-31- format (bits) -0-
Rcode d'opération (6)rs (5)rt (5)rd (5)shamt (5)fonction (6)
jecode d'opération (6)rs (5)rt (5)immédiat (16)
Jcode d'opération (6)adresse (26)

rs , rt et rd indiquent des opérandes de registre ; shamt indique un décalage ; et les champs d’adresse ou immédiats contiennent directement un opérande.

Par exemple, l'addition des registres 1 et 2 et le placement du résultat dans le registre 6 sont codés comme suit :

[ op | rs | rt | rd |shamt| funct] 0 1 2 6 0 32 décimal 000000 00001 00010 00110 00000 100000 binaire

Charger une valeur dans le registre 8, extraite de la cellule mémoire située 68 cellules après l'adresse indiquée dans le registre 3 :

[ op | rs | rt | adresse/immédiat] 35 3 8 68 décimal 100011 00011 01000 00000 00001 000100 binaire

Accès à l'adresse 1024 :

[ op | adresse cible ] 2 1024 décimal 000010 00000 00000 00000 10000 000000 binaire

Bytecode

Le code machine est similaire au bytecode , mais fondamentalement différent . Comme le code machine, le bytecode est généralement généré (par exemple par un compilateur) à partir du code source. Cependant, contrairement au code machine, le bytecode n'est pas directement exécutable par un processeur. Une exception existe pour les processeurs conçus pour utiliser le bytecode comme code machine, tels que le MicroEngine Pascal ou un processeur Java . Si le bytecode est traité par un interpréteur logiciel, cet interpréteur constitue alors une machine virtuelle dont le bytecode représente le code machine.

Stockage

Lors de l'exécution, le code machine est généralement stocké dans la RAM, bien que certains appareils prennent en charge l'exécution depuis la ROM. Quoi qu'il en soit, le code peut également être mis en cache dans une mémoire plus spécialisée afin d'améliorer les performances. Il peut exister différents caches pour les instructions et les données, selon l'architecture.

Du point de vue d'un processus , le code machine réside dans l'espace de code , une partie désignée de son espace d'adressage . Dans un environnement multithread , différents threads d'un même processus partagent l'espace de code ainsi que l'espace de données, ce qui réduit considérablement la surcharge liée au changement de contexte par rapport au changement de processus.

Lisibilité

Le code machine est généralement considéré comme illisible par l'homme , Douglas Hofstadter le comparant à l'examen des atomes d'une molécule d'ADN . Cependant, divers outils et méthodes permettent de comprendre le code machine.

Le désassemblage décode le code machine en langage assembleur, ce qui est possible puisque les instructions assembleur peuvent souvent être mappées une à une aux instructions machine.

Un décompilateur convertit le code machine en un langage de haut niveau , mais le résultat peut être relativement obscurci (difficile à comprendre).

Un programme peut être associé à des symboles de débogage (intégrés à l' exécutable natif ou dans un fichier séparé) permettant de l'associer à du code source externe. Un débogueur lit ces symboles pour aider le programmeur à déboguer le programme de manière interactive. Exemples :

  • Le système d'exploitation SHARE (1959) pour les ordinateurs IBM 709 , IBM 7090 et IBM 7094 permettait le chargement d'un format de code nommé SQUAZE . SQUAZE était une forme binaire compressée de code en langage assembleur et incluait une table des symboles.
  • Les systèmes d'exploitation modernes pour mainframe IBM , tels que z/OS , disposent d'une table de symboles nommée Associated data (ADATA). Cette table est stockée dans un fichier pouvant être généré par l' assembleur de haut niveau IBM (HLASM) , le compilateur COBOL d'IBM et le compilateur PL/I d'IBM , soit sous forme de fichier SYSADATA distinct, soit sous forme d'enregistrements ADATA dans un fichier de sortie d'objet généralisé (GOFF) . Ceci rend obsolètes les enregistrements TEST d' OS/360 , bien qu'il soit toujours possible de les demander et de les utiliser dans la commande TSO TEST.
  • Windows utilise une table de symboles qui est stockée dans un fichier de base de données de programme ( .pdb ).
  • La plupart des systèmes d'exploitation de type Unix proposent des formats de table de symboles appelés stabs et DWARF . Sous macOS et autres systèmes d'exploitation basés sur Darwin , les symboles de débogage sont stockés au format DWARF dans un fichier .dSYM distinct.

    Plus d articles de Worldlex Wiki

    Revenez a l index pour explorer davantage de pages sur l histoire, la science, la culture, la geographie et la societe en francais.

    Explorer l index