Je viens de dire de ne pas céder à la facilité !
Au travail !
Version d'archive
Marre des compilateurs ? Marre de la grammaire ? Envie de parler directement à l'oreille de votre processeur ? Revenez aux sources ! Je vous présente dans l'arbre des connaissances inutiles, la programmation en très bas niveau !
Il existe un mythe parmi les plus endurcis des programmeurs, un Eldorado, où on programme avec des chiffres et des lettres... Des suites sans fin de A, de F, de 5 ou encore de 3 qui se suivent, et qui aboutissent finalement à un objectif commun, envoyer des instruction particulières à une machine statique pour qu'elle s'anime, et réalise un miracle que l'on nomme programme.
Tout le monde a pensé aux pauvres pionniers de la programmation qui codaient avec des 0 et des 1, et certains d'entre vous se sont attaqués à l'assembleur, pour essayer de ressembler un peu plus à ces génies... Mais non, on ne va pas faire de l'obscure language bas niveau où on va potasser un gros pâté de théorie avant de pondre le moindre code...
Ici, on va parler très bas niveau, et on va essayer d'alléger au maximum (au début) la partie théorie, et pratiquer un maximum cette chose qu'on appelle l'Hexadécimal...
Allez petits zéros ! Explorons cette nouvelle branche de l'arbre des connaissances inutiles ! Je vous le dit : Vous aller coder en Hexadécimal !
(Aligné sur la syntaxe du Site du Zéro)
Configuration
recommandée
:
Un rapide petit topo le temps d'exposer la situation, et ainsi arriver toutes les clés en mains dans le feu de l'action !
C'est là qu'on va parler le plus des entrailles de votre machine, comment elle marche et comment on peut lui parler. Pour certains, ils trouveront que c'est un peu mince... Mais j'évite un peu les pavés, on reparlera avec des termes techniques compliqués plus tard.
Qu'est ce que c'est un niveau ? Hein ? Et qu'est ce que c'est un bas ? Et un très ? Stop les question !
(enfin... c'est ce que je vais essayer de vous faire croire)
Comme je l'ai déjà dit, ce tutoriel aura pour but du vous introduire à la programmation très bas niveau. Enfin, normalement, ça n'existe pas, il n'y a que Haut et Bas niveau, mais j'ai fais quelques distinctions personnelles pour avoir une meilleur représentation.
Bon, une petite échelle des niveaux :
L'idée qu'il faut ressortir de cette échelle est que le bas niveau et le très bas niveau sont très proches du fonctionnement de votre processeur. Il en découle plusieurs choses, comme qu'il y a autant de langages bas/très bas niveau que de type de processeurs, ou encore que les boucles, les fonctions et les variables, tel qu'elles sont d'habitude en haut niveau n'existent plus en bas niveau. En très bas niveau, si on résume, on a :
Comme quoi, c'est un peu de la programmation "light", ce qui fait que pour juste écrire un hello word à l'écran on va devoir déployer une usine à gaz.
Par contre, bien qu'il y a cet handicap, le très bas niveau est beaucoup beaucoup plus rapide à exécuter...
(En comparaison avec un language assez haut niveau comme le Visual Basic, il est
30000
fois plus rapide à exécuter ! (un ordre de grandeur))
D'où vient cet différence ? C'est le trajet d'une bête instruction, qui parfois passe par 3 fonctions différentes, le système d'exploitation, son noyau et le DOS avant d'arriver jusqu'à votre processeur.
Vous commencez à saisir ? Bon, voyons de plus près le trajet de l'instruction :
Ainsi, c'est là qu'on voit pourquoi le très bas niveau est beaucoup plus efficace que les langages de haut niveau, qui font des détours et qui perdent énormément en performance... Mais alors, pourquoi avoir créer le Haut niveau ?
Pour saisir la véritable utilité de l'introduction du Haut niveau, voyons au niveau de la compilation...
Qu'est-ce la compilation ? Dans un programme, il y a le "code", qui ressemble à ça :
"If (tata == toto) {printf ("toto est chez lui\n" ; return} "
Et le programme lui-même, qui a été compilé et convertit en instructions plus simple à comprendre (pour une machine, bien sûr ), et ça ressemble à ça :
"¾6ÊG#=›‡D̃ÀܤŸÌÒFIåÁRŒJËÄØj"
Voici un tableau comparatif :
Vous comprenez pourquoi des esprits tordus ont inventés le Haut niveau ? D'ailleurs, si vous regardez bien, le Très Haut et le Très Bas ont une différence par rapport aux autres, il n'ont pas de compilation.
Et vous voyez le code en très bas niveau ? C'est ça qu'on va apprendre à maîtriser !
Ne partez pas ! Les programmes brut du très bas niveau ont trois façon de se lire :
On va ici étudier qu'en Hexadécimal ( Ouuuuf ! ), le binaire étant peu intéressant en soi (et peu compréhensible ).Et on va éviter les caractères ASCII, à moins que vous avez un clavier avec 256 touches et un cerveau mal-formé au point de vouloir essayer.
Je vais vous re-dire un truc :
Il y a autant de langages très bas niveau que de processeurs !
Et encore ! Entre l'architecture (la façon dont on interprète), le fabricant (Intel, Athlon, Pentium...etc) et l'endianness, on peut avoir près de 50 langages différents !
(Sur un ordinateur, car une calculette ou un GPS ne parle pas pareil. )
Ben oui, sauf que je suis bon et généreux, et on va étudier ici sur un processeur qui date de 30 ans, un vieux truc en 16 bit réel x86 en Little-Endian.
En théorie, le votre ayant 30 ans d'avance, n'importe quel processeur un peu standardisé comprendra absolument toutes nos commandes. Dans le cas où vous avez un doute, voici la référence de ce tutoriel :
Processeur Intel Core2 CPU
T5500
cadencé à 1.66Ghz en
32 bit
d'architecture
x86
et un endianness en
Little-endian
.
C'est une configuration de processeur très courante (x86 + 32bit + Little endian) et présent dans la plupart des ordinateurs.
Si vous essayez sur un ordinateur étrange ou encore sur un téléphone portable, ça pourrait poser problème. Mais normalement, vous n'aurez aucun problème.
(Enfin, c'est là la limite entre la théorie et la pratique )Vous commencez à comprendre ? Là, on a juste survolé le fonctionnement global de votre processeur. Maintenant, on va approfondir en parlant du personnage principal, le vrai, l'original, He-xa-dé-ci-maaaaaaal !
Attention ! Lisez attentivement ! On y passe rapidement et si vous n'avez pas comprit, vous serez perdus !
Mais vous savez, quand on programme en haut ou en bas niveau, savoir compter en hexadécimal, c'est un peu de la culture générale.
Donc, qu'est ce que l'hexadécimal ? C'est une base, nous, on compte en base de 10, le décimal :
Chiffres : 0123456789
Nombres : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Et l'hexadécimal, inventé par des esprits tordus, est une base de 16 :
Chiffres : 0123456789ABCDEF
Nombres : 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14
Ne partez pas, l'hexadécimal n'est pas méchant, il est juste différent.
Maintenant, voyons comment passer d'une base à l'autre :
C'est très facile !
Pour les curieux qui n'ont pas peur des conversion, voici des liens complémentaires qui pourront vous l'apprendre mieux que moi :
Passer du décimal vers une autre base (Wikipédia)
Passer d'une base quelconque à une autre (Wikipédia)
Un tutoriel de Dentuk plein de bon sens (
Site du Zéro !
)
On va travailler en Hexadécimal, donc, il va vous falloir un éditeur hexadécimal :
Le must :
EditHexa 7.8
!
Bon, voyons comment s'en servir :
1. Vous ouvrez le logiciel, normalement, vous avez un écran blanc avec pleins de gros boutons en haut. Cliquez sur la feuille cornée pour faire un nouveau fichier.
2. Placez le sur le bureau, appelez-le "Testeur.com" et mettez lui une taille de 256 (on prend de la marge...).
3. Faites deux clic sur un "00", voilà, maintenant, vous pouvez écrire en Hexadécimal !
C'est bon ! Vous savez tout !
On va faire un petit TP ! Placez vous sur le premier octet (case), et écrivez cecin:
BA0F01B409CD21B408CD21B44CCD214875676820212054752061732072657573736973202124
Bon, avant que vous mettiez deux heures à tout copier , voici une astuce :
1. Allez dans "outils avancé"
2. Ajouter une séquence
3. "Offset en hexadécimal = 0", puis "Emplacement = écraser le fichier original"
4. Collez votre séquence dans le champ central, puis validez !
Normalement, vous aurez toute votre séquence commençant tout en haut à droite et fessant 2 lignes et demi. Allez dans "outils avancés", enregistrer, et écrasez l'original.
Allez sur votre bureau et exécutez "Testeur.com". (Appuyez sur une touche pour le terminer.
Maintenant, regardez à droite, sur votre fichier mais en caractères normaux... MAGIE ! Que voyez vous ?
Allez, un peu d'aide :
º´ Í!´Í!´LÍ!Hugh ! Tu as reussis !$
Ahah ! Vous voyez, votre chaîne de caractère a été conservée !
Ainsi, outil pratique, lorsque je vous donnerais des corrigés d'exercices, vous pourrez directement insérer votre code.
D'ailleurs, saisissez aussi l'utilité du parallélisme entre l'Hexadécimal à droite et le texte à gauche :
On pourra directement écrire notre chaîne de caractère !
(Au lieu de faire une conversion laborieuse pour chaque caractèreRetenez surtout une chose :
Gardez sous la main votre fidèle calculatrice Windows !
Souquez ferme moussaillon ! Voici la tempête qui s'annonce !
Tout à coup, surgissant des eaux tel un kraken des temps anciens, le terrible Hello Word vous attaque !
(Heureusement que Sbirematqui arrive à la fin ! )
Plus sérieusement, voici une introduction digne de ce nom :
L'exercice du "Hello Word" est l'exercice de base par excellence !
Il consiste à afficher une chaîne de caractère à l'écran, un
"Hello Word". Le but de cette partie sera d'introduire suffisamment de bases pour arriver à vous mener à réussir cet exercice, voir même en faire un jeu très très sommaire.
Il est normalement très simple pour des programmes haut niveau, mais là, on est pas en haut, on est en bas.
(Et c'est très très dur, en bas...
 
Bon, on attaque l'entrée, les registres seront tout le temps présent dans vos programmes, normal, c'est l'essentiel même du bas niveau.
Préparez vous ! Cette journée sera une journée avec un soleil rouge !
Bon, déjà, qu'est ce que une variable ?
Prenons un exemple :
Tous les matins, je mange 100g de céréales.
On pourrait dire :
Prenons un nombre noté Ma (pour masse)puis définissons Ma à 100g.
Tous les matins, je mange Ma de céréales.
Quelle utilité ? Vous allez voir :
Tous les matins, si il fait beau je mangerais 100g de céréales, si il fait mauvais je mangerais 120g de céréales.
Ou sinon :
Prenons un nombre noté Ma (pour masse) puis définissons Ma à 100g.
Si il fait mauvais, j'ajoute 20g à Ma.
Tous les matins, je mange Ma de céréales.
Voilà une bonne idée de ce que c'est une variable : Une représentation d'une valeur qui peut changer. Dans notre petit monde du Bas niveau, il existe plusieurs types de variable :
-Les registres, prédéfinis par 2 lettres (enfin, là, on ne travaille qu'avec 2 lettres) seulement et très rapide pour l'ordinateur à utiliser. Il sont stockés sur des petites mémoires directement dans le processeur. Ils sont assez étroits, ils ne contient que 16bits, c'est à dire un nombre hexadécimal à 4 chiffres, donc de 0 à 65536 dans notre bon vieux système décimal.
-Les adresses, c'est tout simplement une adresse d'un point précis dans la mémoire vive. Ce point fait 2 nombre de 4 chiffres en hexadécimal (Nous travaillons ici en 16 bit, des adresses de type ????x????, il existe actuellement des processeurs plus évolués tournant en 32 ou 64bit), donc de 0x0 à 65536x65536, et la mémoire est plus lente à accéder... L'intérêt ? Très simple ! Si on connaît le point A et B, on peut savoir toutes les coordonnées des points entre A et B ! Donc beaucoup plus volumineux qu'un simple registre...
On ne détaillera ici, pour notre hello word, que les plus essentiels, les registres dits "généraux" :
Bon, voilà les généraux... C'est un peu vague, mais pour l'instant, ça suffira. Juste une dernière chose, chaque registre général est composé de deux parties, la partie haute et la partie basse, de chacune de 2 chiffres hexadécimal. Ainsi, pour de petits chiffres, on pourra stocker deux chiffres. Pour accéder à ces mini-registres (ou sous-registre), on va remplacer le X par un H (Hight, partie haute) ou par un L (Low, partie basse). Ainsi, on aura 4 registres généraux, et 8 sous-registres :
AX, BX, CX, DX
AH, AL, BH, BL, CH, CL, DH, DL
Bon, trêve de plaisanteries, passons à la pratique des registres !
Aïe ! Et là, c'est le drame ! Nous allons commencer à voir des instructions en Hexadécimal, et là ça se corse...
Pour définir un registre à une valeur précise, voici comment ça se goupille :
La commande de définition d'un registre général ou d'un sous registre général est la suivante : le B
Puis, associé au B, on a le registre/sous-registre qu'on veut définir, sauf qu'ils sont sous forme Hexadécimale, voici la correspondance :
0 = AL
1 = CL
2 = DL
3 = BL
4 = AH
5 = CH
6 = DH
7 = BH
8 = AX
9 = CX
A = DX
B = BX
C'est pas compliqué ! Ils sont dans l'ordre ! Bon, maintenant qu'on sait comment choisir son registre et utiliser la fonction, voyons comment entrer la valeur...
Pour cela, prenons un exemple, définissons le registre DH à B4 (Bah oui, toutes les valeurs sont en hexa, donc, munissez vous de la calculette windows en mode scientifique !). On commence par B, puis on accole le 6, et on met la valeur :
B6 B4
Voilà ! Pas compliqué !
Maintenant, passons à la vitesse supérieur en définissant AX à 01FA (ne pas oublier que les X sont des registres "entiers", qui font 2 paquets de 2 chiffre). On prend le B, on met le 8, et on a :
B8 FA 01
AHHHH ! (ou ALLLL !) Quel est ce sort ? Pour 01FA (ou 506 en décimal), on a FA01 ! Normal, car il ne faut pas oublier comment votre ordinateur l'exécute votre programme (son endianness) :
B8
FA 01 --> Il lit la commande qui lui dit "définis AX avec les chiffres qui vont suivre)
B8 FA
01 --> Il lit la première partie, et là, il met AL à FA.
B8 FA 01
--> Il lit la seconde partie, et là, il met AH à 01.
Encore sous le choc de la terrible vérité, vous vacillez. Définir un registre entier est comme définir ses deux petits sous-registres ! (Mais ça prend moins de place)
Attention, idée sadique qui germe dans ma tête :
Maintenant qu'on sait définir un registre à une valeur fixe, pourquoi pas le définir à une variable, à un autre registre ?
Avant de se lancer, voyons ce que nous allons faire :
Voici ce qu'on a fait juqu'à maintenant :
1 >> AX, alors AX = 1
Et voici ce qu'on va apprendre ici :
1 >> AX puis AX >> DX, alors on aura AX = 1 et DX = AX (donc 1)
Ce sera toujours une commande, et elle se consitue ici de deux parties :
-De "89" , qui dit à l'ordinateur "prend le registre qui arrive (AX dans notre exemple) et met le dans le suivant (DX dans notre exemple)"
-Et de ??, représentant nos deux registres AX et DX, dont la syntaxe est plus compliquée...
Déjà, à cause de l'endianness, la définition d'un registre par un autre registre est "à l'envers" (pour définir DX à AX, on écrit "prend AX et met le dans DX", mais en plus, les correspondance entre la commande hexa et les registres ne sont pas les mêmes... (c'est là que ça devient sadique )
Dans notre ??, le
DEUXIÈME
chiffre indique le registre qu'on va définir (DX), et le
premier
le registre qui contient la valeur (AX).
Le
premier
chiffre (le registre qui contient la valeur, AX) a cette syntaxe :
C
pour le registre
AX ou CX
D
pour le registre
DX ou BX
A mais ! C'est pas du jeu ! C'est quoi ce "ou" ?
Vous allez voir avec la syntaxe du deuxième chiffre (le registre qu'on définit, DX) :
0 =
AX
pour les registres
AX et DX
1 =
CX
pour les registres
AX et DX
2 =
DX
pour les registres
AX et DX
3 =
BX
pour les registres
AX et DX
Et :
8 =
AX
pour les registres
CX et BX
9 =
CX
pour les registres
CX et BX
A =
DX
pour les registres
CX et BX
B =
BX
pour les registres
CX et BX
(C'est un peu complexe, mais je vais donner plus tard un exemple.)
Et pourquoi ça ?
Tout simplement, on compacte et on économise la place, au lieu de faire 256 commandes.
Récapitulons ce que nous venons de voir :
89 C[0-3]
(C pour AX ou CX, puisqu'on a 0-3)
|
|->On définis un registre à la valeur de AX.
89 C[8-B]
(C pour AX ou CX, puisqu'on a 8-B)
|
|->On définis un registre à la valeur de CX
89 D[0-3]
(D pour DX ou BX, puisqu'on a 0-3)
|
|->On définis un registre à la valeur de DX.
89 D[8-B]
(D pour DX ou BX, puisqu'on a 8-B)
|
|->On définis un registre à la valeur de BX.
Vache hein ?
Pour conclure, voici notre exemple du début en code hexa :
89 C2
Traduit en français :
"Tu prend
AX
et tu le met dans
DX
"
Maintenant, (et oui ! Toujours dans la manipulation des registres) on va voir comment ajouter une valeur à un registre...
Ici, on va plus faire un :
1 >> AX ou un AX >> DX
Mais on va additionner une valeur ou un registre :
AX + 1 >> AX ou DX + AX >> DX
En gros, on ajouteras quelque chose.
On va aller vite, ce n'est pas d'une complexité absolue ( ).
Syntaxe pour les petites valeurs (pas très important, on retiendra surtout les grandes), de 00 à FF :
83 + C + Registre + Valeur
0 = AX
1 = CX
2 = DX
3 = BX
Ce qui fait, que si on veut ajouter 5 au registre CX, on aura :
83 C1 05
Alors, pour ajouter 12 à DX, on fait ?
83 C2 0C
(Oui, c'était une question piège )
Maintenant, voyons la syntaxe pour les grandes valeurs, de 0000 à FFFF (Retenez là, on pourra aussi l'utiliser pour les petites)
On a :
81 + C + Registre + Valeur
(Rappel : La valeur est toujours inversée, donc on aura pour B049 --> 49 B0)
C'est là qu'il y a une exception ! Et oui, regardez la liste suivant où on ajoute 0C1F à tous les registres :
AX -->
05 1F 0C
CX -->
81 C1 1F 0C
DX -->
81 C2 1F 0C
BX -->
81 C3 1F 0C
Ahh ! Oui, pour ajouter une valeur à AX, opération
très très
courante, on a simplifié pour économiser de la place en remplaçant le 81 C0 par un petit 05 .
Et
enfin, pour ajouter un registre à un autre :
Syntaxe :
01 + Code registre
Le code registre est le même que pour définir un registre dans un autre (moins sadique là, non ? ), donc, on a :
01 C[0-3]
|
|->Ajoute à un registre la valeur de AX
01 C[8-B]
|
|->Ajoute à un registre la valeur de CX
01 D[0-3]
|
|->Ajoute à un registre la valeur de DX
01 D[8-B]
|
|->Ajoute à un registre la valeur de BX
Pour détendre l'atmosphère, on va faire un petit TP qui ne sert strictement à rien.
Donc, écrivez-moi un programme qui définis AX à B0A4, puis on définis tous les registres généraux sur AX. Ajoutez à CX la valeur 1001 et à DX la valeur 51. Ensuite, vous allez ajouter à DX le registre BX, puis à CX le registre DX et enfin à AX le registre CX. Pour finir, vous allez définir DX à la valeur AX.
Question bonus : Quel sera la valeur de DX en fin de programme ?
J'explique d'une autre façon :
AX << B0A4
CX << AX
DX << AX
BX << AX
CX << CX + 1001
DX << DX + 0051
DX << DX + BX
CX << CX + DX
AX << AX + CX
DX << AX
C'est peut-être plus claire pour certains d'entre vous...
Réfléchissez bien ! Ne trichez pas ! Voici la correction, mais ne cédez pas à la facilité !
Spoiler (Sélectionnez le texte dans le cadre pointillé pour le faire apparaître)
Je viens de dire de ne pas céder à la facilité !
Au travail !
Voici la correction, si t'a bien travaillé :
Spoiler (Sélectionnez le texte dans le cadre pointillé pour le faire apparaître)
La solution avec les espaces :
B8 A4 B0 89 C1 89 C2 89 C3 81 C1 01 10 83 C2 51 01 DA 01 D1 01 C8 89 C2
Et celle sans espace, copier-collable (mais pour ce TP, ça ne sert à rien ) :
B8A4B089C189C289C381C1011083C25101DA01D101C889C2
Cette solution marche, est immuable et a été même assemblée en assembleur. Si vous êtes arrivés à ce résultat, je dis bravo ! Vous avez tout compris !
Question bonus pour vérifier si vous savez compter en Hexa :
B04A + B04A + B04A + B04A + 1001 + 51 = 2D2E2
Remarque : Cette valeur n'aurait jamais pu être stockée dans DX, limité à FFFF, ou 65536. La, on atteint 185058 . On aurait eu besoin d'utiliser les registres 32bits, non vus dans ce chapitre.
Premier contact avec l'Hexadécimal, ça choque, hein ? Rassurez vous, le temps de prendre une douche froide, et on repars !
posté par Sbirematqui il y a plus de 13 ans , édité par Sbirematqui il y a plus de 13 ans
© Copyright 2002-2024 Aeriesguard.com - Mentions légales
Aerie's Guard V 7.0 réalisé par Ertaï, designé par Ivaldir, illustré par Izual et Sophie Masure