Recherche…


Remarques

Assembly est un nom général utilisé pour de nombreuses formes de code machine lisibles par l'homme. Il diffère naturellement beaucoup entre les différents processeurs (Central Processing Unit), mais sur un seul processeur, il peut exister plusieurs dialectes d'Assemblage incompatibles, chacun compilé par un assembleur différent, dans le code machine identique défini par le créateur du processeur.

Si vous souhaitez poser une question sur votre propre problème d'assemblage, indiquez toujours quel matériel vous utilisez et quel assembleur vous utilisez, sinon il sera difficile de répondre à votre question en détail.

L'apprentissage de l'assemblage d'un seul processeur particulier aidera à apprendre les bases de différents processeurs, mais chaque architecture matérielle peut présenter des différences considérables en termes de détails.

Liens:

Assemblage X86 Wikibook

introduction

Le langage d'assemblage est une forme lisible par l'homme du langage machine ou du code machine qui correspond à la séquence réelle de bits et d'octets sur laquelle la logique du processeur fonctionne. Il est généralement plus facile pour les humains de lire et de programmer des mnémoniques que binaires, octaux ou hexadécimaux. Les humains écrivent donc généralement du code en langage assembleur, puis utilisent un ou plusieurs programmes pour le convertir en langage machine.

EXEMPLE:

mov eax, 4
cmp eax, 5
je point

Un assembleur est un programme qui lit le programme en langage assembleur, l’analyse et produit le langage machine correspondant. Il est important de comprendre que contrairement à un langage comme C ++ qui est un langage unique défini dans un document standard, il existe de nombreux langages d'assemblage différents. Chaque architecture de processeur, ARM, MIPS, x86, etc. a un code machine différent et donc un langage d'assemblage différent. De plus, il existe parfois plusieurs langages d'assemblage différents pour la même architecture de processeur. En particulier, la famille de processeurs x86 a deux formats populaires, souvent appelés syntaxe de gaz (le gas est le nom de l'exécutable pour GNU Assembler) et la syntaxe Intel (nommée d'après l'auteur de la famille de processeurs x86). Ils sont différents mais équivalents en ce sens que l'on peut généralement écrire n'importe quel programme dans l'une ou l'autre syntaxe.

Généralement, l'inventeur du processeur documente le processeur et son code machine et crée un langage d'assemblage. Il est courant que ce langage d'assemblage soit le seul utilisé, mais contrairement aux auteurs de compilateurs qui tentent de se conformer à un standard de langage, le langage d'assemblage défini par l'inventeur du processeur n'est généralement pas la version utilisée par ceux qui écrivent des assembleurs. .

Il existe deux types généraux de processeurs:

  • CISC (ordinateur de jeu d'instructions complexes): possède de nombreuses instructions différentes et souvent complexes en langage machine

  • RISC (Reduced Instruction set Computers): en revanche, les instructions sont moins nombreuses et plus simples

Pour un programmeur en langage assembleur, la différence réside dans le fait qu’un processeur CISC peut recevoir de nombreuses instructions à apprendre, mais il existe souvent des instructions adaptées à une tâche particulière, alors que les processeurs RISC ont des instructions moins nombreuses et complexes. pour écrire plus d'instructions pour faire la même chose.

Les autres compilateurs de langages de programmation produisent parfois des assembleurs en premier, qui sont ensuite compilés en code machine en appelant un assembleur. Par exemple, gcc utilise son propre assembleur de gaz en phase finale de compilation. Le code machine produit est souvent stocké dans des fichiers objets , qui peuvent être liés dans le fichier exécutable par le programme de l'éditeur de liens.

Une "chaîne d'outils" complète consiste souvent en un compilateur, un assembleur et un éditeur de liens. On peut alors utiliser cet assembleur et cet éditeur de liens directement pour écrire des programmes en langage assembleur. Dans le monde GNU, le paquet binutils contient l'assembleur et l'éditeur de liens et les outils associés; ceux qui sont uniquement intéressés par la programmation en langage d'assemblage n'ont pas besoin de gcc ou d'autres packages de compilateurs.

Les petits microcontrôleurs sont souvent programmés uniquement en langage d'assemblage ou dans une combinaison de langage d'assemblage et d'un ou plusieurs langages de niveau supérieur tels que C ou C ++. Ceci est fait car on peut souvent utiliser les aspects particuliers de l' architecture du jeu d'instructions pour que de tels dispositifs écrivent un code plus compact et efficace que ce qui serait possible dans un langage de niveau supérieur et ces dispositifs ont souvent une mémoire et des registres limités. De nombreux microprocesseurs sont utilisés dans des systèmes embarqués qui sont des périphériques autres que les ordinateurs à usage général qui ont un microprocesseur à l'intérieur. Des exemples de tels systèmes embarqués sont les téléviseurs, les fours à micro-ondes et l'unité de commande du moteur d'une automobile moderne. Beaucoup de ces dispositifs n’ont ni clavier ni écran, de sorte qu’un programmeur écrit généralement le programme sur un ordinateur à usage général, exécute un assembleur croisé (ainsi appelé parce que ce type d’assembleur produit du code pour un type de processeur différent de celui sur lequel il est exécuté). ) et / ou un compilateur croisé et un cross-linker pour produire du code machine.

Il existe de nombreux fournisseurs de tels outils, aussi variés que les processeurs pour lesquels ils produisent du code. Beaucoup de processeurs, mais pas tous, ont également une solution open source comme GNU, sdcc, llvm ou autre.

Langage machine

Le code machine désigne les données, en particulier le format de machine natif, directement traité par la machine, généralement par le processeur appelé CPU (Central Processing Unit).

L'architecture informatique commune (architecture von Neumann ) comprend un processeur à usage général (CPU), une mémoire à usage général - stockant à la fois le programme (ROM / RAM) et les données traitées et les périphériques d'entrée / sortie (périphériques E / S).

Le principal avantage de cette architecture est la simplicité relative et l’universalité de chacun des composants - par rapport aux machines informatiques précédentes (avec un programme câblé dans la construction de la machine), ou des architectures concurrentes (par exemple l’architecture Harvard séparant la mémoire du programme de la mémoire). Les données). Le désavantage est un peu moins performant. À long terme, l’universalité permettait une utilisation flexible, qui dépassait généralement le coût des performances.

Comment cela se rapporte-t-il au code machine?

Le programme et les données sont stockés dans ces ordinateurs sous forme de nombres, dans la mémoire. Il n'y a pas de véritable moyen de distinguer le code des données, donc les systèmes d'exploitation et les opérateurs de machine donnent des indications sur le processeur, à quel point de la mémoire commence le programme, après avoir chargé tous les numéros en mémoire. Le CPU lit alors l'instruction (numéro) stockée au point d'entrée et la traite rigoureusement, en lisant séquentiellement les prochains numéros en tant qu'instructions supplémentaires, à moins que le programme lui-même n'indique à la CPU de continuer l'exécution ailleurs.

Par exemple, deux nombres de 8 bits (8 bits regroupés sont égaux à 1 octet, soit un nombre entier non signé compris entre 0 et 255): 60 201 , lorsqu'ils sont exécutés en tant que code sur la Zilog Z80, seront traités comme deux instructions: INC a (valeur incrémentée dans le registre a par un) et RET (retour de la sous-routine, pointant le processeur pour exécuter les instructions de différentes parties de la mémoire).

Pour définir ce programme, un humain peut entrer ces nombres par un éditeur de mémoire / fichier, par exemple dans hex-editor sous la forme de deux octets: 3C C9 (nombres décimaux 60 et 201 écrits en codage base 16). Ce serait la programmation en code machine .

Pour faciliter la tâche de la programmation CPU pour les humains, un programme Assembler a été créé, capable de lire un fichier texte contenant quelque chose comme:

subroutineIncrementA:
    INC   a
    RET

dataValueDefinedInAssemblerSource:
    DB    60          ; define byte with value 60 right after the ret

sortie de la séquence de nombres hexadécimaux d'octets 3C C9 3C , entourée de nombres supplémentaires facultatifs spécifiques à la plate-forme cible: indiquer quelle partie de ce code est exécutable, où est le point d'entrée du programme (la première instruction), quelles parties sont codées données (non exécutables), etc.

Remarquez comment le programmeur a spécifié le dernier octet avec la valeur 60 comme "données", mais du point de vue de la CPU, il ne diffère en rien de INC a octet. Le programme d'exécution doit naviguer correctement sur les octets préparés en tant qu'instructions et traiter les octets de données uniquement en tant que données pour les instructions.

Une telle sortie est généralement stockée dans un fichier sur un périphérique de stockage, chargée ultérieurement par le système d’exploitation ( système d’exploitation - un code machine déjà exécuté sur l’ordinateur, permettant de manipuler l’ordinateur ) point d'entrée du programme.

Le processeur ne peut traiter et exécuter que du code machine - mais tout contenu de mémoire, même aléatoire, peut être traité en tant que tel, bien que le résultat puisse être aléatoire, allant de " crash " détecté O périphériques, ou endommagement des équipements sensibles connectés à l'ordinateur (pas un cas commun pour les ordinateurs domestiques :)).

Le processus similaire est suivi par de nombreux autres langages de programmation de haut niveau, en compilant la source (forme de texte lisible par un humain) en chiffres, représentant le code de la machine (instructions natives du CPU) ou code de machine virtuelle spécifique à la langue, qui est ensuite décodé en code machine natif pendant l'exécution par un interpréteur ou une machine virtuelle.

Certains compilateurs utilisent l'assembleur comme étape intermédiaire de la compilation, traduisant tout d'abord le source sous la forme Assembler, puis exécutant l'outil Assembleur pour en extraire le code machine final (exemple GCC: exécutez gcc -S helloworld.c pour obtenir une version assembleur du programme C) helloworld.c ).

Bonjour tout le monde pour Linux x86_64 (Intel 64 bit)

section .data
    msg db "Hello world!",10      ; 10 is the ASCII code for a new line (LF)

section .text
    global _start

_start:
    mov rax, 1
    mov rdi, 1
    mov rsi, msg
    mov rdx, 13
    syscall
    
    mov rax, 60
    mov rdi, 0
    syscall

Si vous voulez exécuter ce programme, vous devez d'abord installer Netwide Assembler , nasm , car ce code utilise sa syntaxe. Utilisez ensuite les commandes suivantes (en supposant que le code se trouve dans le fichier helloworld.asm ). Ils sont nécessaires pour l'assemblage, la liaison et l'exécution, respectivement.

  • nasm -felf64 helloworld.asm
  • ld helloworld.o -o helloworld
  • ./helloworld

Le code utilise sys_write syscall de Linux. Ici vous pouvez voir une liste de tous syscalls pour l'architecture x86_64. Lorsque vous tenez également compte des pages de manuel de write et exit , vous pouvez traduire le programme ci-dessus en C qui fait la même chose et est beaucoup plus lisible:

#include <unistd.h>

#define STDOUT 1

int main()
{
    write(STDOUT, "Hello world!\n", 13);
    _exit(0);
}

Deux commandes sont nécessaires ici pour la compilation et la liaison (première) et pour l'exécution:

  • gcc helloworld_c.c -o helloworld_c .
  • ./helloworld_c

Hello World pour OS X (x86_64, gaz de syntaxe Intel)

.intel_syntax noprefix

.data

.align 16
hello_msg:
    .asciz "Hello, World!"

.text

.global _main
_main:
    push rbp
    mov rbp, rsp

    lea rdi, [rip+hello_msg]
    call _puts

    xor rax, rax
    leave
    ret

Assembler:

clang main.s -o hello
./hello

Remarques:

Exécution d'un assembly x86 dans Visual Studio 2015

Étape 1 : Créez un projet vide via Fichier -> Nouveau projet .

entrer la description de l'image ici

Étape 2 : Cliquez avec le bouton droit sur la solution du projet et sélectionnez Build Dependencies-> Build Customizations .

Étape 3 : Cochez la case ".masm" .

entrer la description de l'image ici

Étape 4 : Appuyez sur le bouton "ok" .

Étape 5 : Créez votre fichier d'assemblage et saisissez-le:

.386
    .model small
        .code

            public main
                main proc

                    ; Ends program normally

                    ret
                main endp
            end main

Étape 6 : Compiler!

entrer la description de l'image ici



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow