L’assembleur x86 avec NASM

Découvrez le père de tous les langages de programmation ! Un des pères, en tout cas…

a marqué ce sujet comme résolu.

Malheureusement, ce tutoriel qui était en bêta a été supprimé par son auteur.

J’en avais parlé, il est à présent de retour… mon cours d’introduction à l’assembleur x86(_64) est à nouveau disponible à la lecture sur ce site. Pour ceux qui n’auraient pas suivi la première mouture de la bête (et sachant que l’ancien sujet de bêta a été supprimé quand j’ai supprimé le tuto), voici un petit résumé.

Du vieux…

Je trouve que la plupart, si ce n’est la totalité, des cours sur l’assembleur x86 que l’on peut trouver sur Internet ou en livre sont nuls à chier. Ouais, je balance les SCUD directement… Il y a plusieurs raisons à cela.

La première, c’est que ces cours commencent généralement par enseigner le mode réel (16 bits), et souvent ne vont pas plus loin. Problème : cela fait bien depuis 1995 que le mode réel est considéré comme obsolète. Sur les systèmes d’exploitation récents, qui fonctionnent en mode 64 bits, il est même généralement impossible de faire tourner des programmes en mode réel, et il faut recourir à des émulateurs.

De mon côté, j’attaque directement par de l’assembleur 64 bits, pleinement intégré dans un système d’exploitation, et ce n’est que plus tard dans l’apprentissage qu’on pourra, éventuellement, revenir vers les autres modes de fonctionnement, voire se passer de système d’exploitation, tout à la fin.

La seconde, c’est qu’ils enseignent l’assembleur comme si c’était quelque chose de théorique et éthéré : il n’y a quasiment aucune mise en pratique, et les cours se contentent d’accumuler des dizaines et des dizaines de notions les unes à la suite des autres.

On m’a récemment renvoyé vers le cours en bêta sur OCR, et c’est exactement ça : il faut attendre le septième chapitre pour avoir un Hello World. Le premier livre avec lequel j’ai appris l’assembleur ne m’avait toujours pas enseigné comment afficher un simple texte à l’écran après plus de 250 pages de lecture. Et je pourrais continuer les exemples ainsi…

Je suis pour ma part persuadé que l’aspect rébarbatif et difficilement accessible de l’assembleur est en partie dû à cette approche. J’ai donc fait le choix d’amener aussi vite que possible à la pratique, avec un TP dès le quatrième chapitre, et des chapitres organisés non par thèmes (« les registres ») mais en fonction des outils nécessaires pour atteindre l’objectif suivant de mise en pratique.

Pour le reste, c’est un cours pour débutants. Je ne pars pas du principe que le lecteur connaît le C ou quelque autre langage de programmation, seulement qu’il a lu le cours d’intro à la programmation, et qu’il est un peu familier de son système d’exploitation.

… et du neuf !

Pour autant, il y a eu quelques changements plus ou moins importants par rapport à la dernière fois.

Tout d’abord, maintenant que le cours d’introduction à la programmation existe, j’ai un peu nettoyé le chapitre d’introduction, de manière à ne pas faire trop de redites.

Ensuite, et c’est certainement le changement le plus important : j’ai abandonné l’idée de me limiter à Linux. Je me suis dit que l’essentiel du cours concerne l’assembleur lui-même, et pas les appels systèmes, et qu’il serait dommage que les windowsiens ou applistes passent à côté pour une bête question d’OS.

Après quelques recherches, il s’avère que, OS X ayant la bonne idée d’être un BSD, les appels systèmes y sont quasiment identiques que sous Linux, et de même sous tous les BSD et sous Solaris. Seul Windows ne fait rien comme tout le monde, mais j’ai réussi à trouver des solutions, avec Wine et autres combines, pour pouvoir contourner le problème et tester quand même les programmes.

C’est donc un cours totalement multiplate-forme que je vous offre cette fois, même si dans un premier temps, Windows sera un peu laissé de côté, le temps d’acquérir les notions nécessaires à comprendre comment fonctionne son système d’appels système.

Enfin, le plan a été un peu revu. On a déjà discuté avec un certain nombre de gens de l’idée d’accélérer la validation des contenus, en publiant les gros contenus étape par étape, plutôt que d’un bloc quand tout est écrit, et en faisant participer les validateurs dès l’étape de la bêta, pour que la validation proprement dite ne soit plus qu’une formalité.

C’est pourquoi j’ai laissé tomber les parties sur le mode réel et le mode protégé, et adopté un plan de moyen-tuto : je basculerai sur un plan de big-tuto quand j’aurai suffisamment de chapitres pour le justifier.

J’ai par ailleurs bien conscience que 4 chapitres, c’est trop peu de contenu pour qu’il soit validé en l’état. Cependant, mon plan est fait de telle manière que ces quatre premiers chapitres fonctionnent ensemble, et que je ne les modifierai donc pas en rédigeant les suivants.

J’invite donc cordialement un validateur à me donner d’ores et déjà le feu vert sur ces premiers chapitres, lorsque les retours de la bêta se seront taris, bien sûr, afin de ne pas avoir à repasser dessus quand j’aurai écrit les chapitres suivants.

Et sur ces bonnes et longues paroles, je vous laisse à votre lecture.

+8 -0

Et bam, il a encore frappé ! Mais tu ne t'en sortiras pas comme ça :

Première approche de l’assembleur

L’assembleur, qu’es acò ?

afin de leur inculquer le maniement des bits

J'aurais juré qu'il existe un nom plus court pour parler de ça.

Il s’agit simplement d’écrire chaque instruction

Il me semble intéressant de développer un peu cette notion d'instruction. Par exemple, tu pourrais dire juste au-dessus que ces successions de bits sont organisées en instructions, prenant des paramètres. Tu pourrais étayer en donnant deux-trois exemples simplistes (genre lire une donné en mémoire, faire une addition, etc.). J'ai personnellement mieux assimilé la phrase "l’assembleur n’est ni plus ni moins que du code machine à visage humain" quand j'ai suivi mes premiers cours d'architecture des processeurs, apprenant ainsi qu'on stockait des instructions dans des registres.

Objectivement, pour à peu près tout ce que vous pourriez vouloir faire, il est plus pratique de coder dans un langage de haut niveau : le C/C++, le PHP, le Perl, le Haskell, etc. Les programmes qui nécessitent vraiment l’assembleur sont de plus en plus rares, et ne sont pas vraiment adaptés à des débutants : par exemple, coder un pilote pour une carte graphique demande d’être très près de la machine

Tu n'avais pas trop détaillé cette notion de "bas-niveau" ou "proche de la machine" dans le tutoriel sur les bases de la programmation et je crois que ça pose souci pour comprendre ce passage. On peut s'en passer je pense, mais peut-être pourrais-tu, maintenant que tu as un peu parlé des bits et des instructions, détailler la notion ? J'avoue ignorer comment tu pourrais faire ça de manière pas trop lourde. :(

par exemple, coder un pilote pour une carte graphique demande d’être très près de la machine

Pas sûr que la notion de pilote soit nécessairement assimilée par le lecteur.

Une dernière question pourquoi

Petit manque de ponctuation ? :P

Comment on code en assembleur

d’autre part, parce que les documents de référence d’Intel utilisent cette syntaxe et qu’il vous sera plus facile d’y accéder qu’en ayant appris la syntaxe AT&T.

Pourquoi se baserait-on sur les documents de référene d'Intel ? :)

Ces outils sont appelés des directives, et sont propres à chaque logiciel d’assemblage, par opposition aux instructions qui sont définies par le fabricant du processeur et sont les mêmes pour tous les logiciels d’assemblage.

Il faudrait que je relise à tête reposé mais, sur le coup, je m'emmêle les pinceaux entre x86 vs ARM, syntaxe (Intel vs AT&T), directives (NASM/MASM…) et instructions, propres à chaque fabricant.

Premier exemple plein d’originalité

Si ce n’est pas le cas, que vous êtes sous un système d’exploitation 32 bits ou que votre processeur est ancien et ne possède pas le mode long, sachez que vous devrez malgré tout lire la suite de ce cours.

J'ai un peu bogué là-dessus, croyant que tu nous forçais à lire ton cours. :P "sachez que vous devrez malgré tout lire la partie sur x84" me semble plus clair. Mais c'est un détail.

Changeons de registre

Notre première instruction

Enfin, vous avez vu que MOV et RAX sont tout à tour

"tour à tour" ?

C’est qu’avec nasm, les instructions ne sont pas sensibles à la casse

"NASM" ?

; Votre code personnel se trouve ici.

L'ambiguité est levée plus bas, mais on pourrait croire que tu parles des lignes plus bas. Peut-être pourrais-tu ajouter un commentaire du genre ; Puis, à ajouter à la fin de chaque programme :. C'est un détail.

à vous de palier à ma paresse

"pallier"

RAX fait 64 bits de long

Ca tient dans un processeur ça ?1

Ce n’est pas là dedans

"là-dedans"

Plus on est de fous, moins il y a de riz

Là encore, il s’agit d’une pure convention. Et elle est un peu plus complexe que l’ASCII, alors ouvrez grand vos mirettes pour le système du complément à deux.

J'avais hésité en lisant le passage sur les préfixes des valeurs immédiates numériques mais là je pense que maîtriser la notion de base (décimale, hexadécimale…) devrait être un pré-requis. :)

Pour éviter ce désagrément, le processeur stocke le résultat de l’opération MUL non dans un registre de 64 bits, mais dans un « registre fictif » de 128 bits

On pourrait se demander si 128 bits suffisent. Peut-être compléter la phrase avec un truc du genre : "128 bits, ce qui suffit, je vous laisse vous en convaincre, à conserver toute l'information". ^^

Pour une poignée de directives

Système ! SYSTÈME !!

Aussi, si ces deux registres contiennent une valeur importante pour votre programme, vous devez impérativement les sauver quelque part avant de faire un appel système.

Peut-être compléter en disant que, pour l'instant, on ne peut faire cette sauvegarde que dans un autre registre mais que plus tard, si jamais ils sont déjà tous pleins, on aura les outils pour stocker la valeur ailleurs. :)

Label Hélène de Troie

Bon, mon coco, tu vas arrêter de raconter n’importe quoi : tu nous a dit toi-même

as

Il y a ici à la fois des formes correctes et des formes fautives.

Je ne suis pas un expert en pédagogie, aussi je me demande s'il est judicieux de mélanger bonnes et mauvaises pratiques.

en effet, si le texte contient un guillemet simple (qui sert généralement à noter l’apostrophe dans les textes écrits sur ordinateur), et que la chaîne est entourée de guillemets simples, cela va faire boguer notre cher NASM.

Peut-être ajouter une note pour dire qu'on a le même problème avec un guillemet dans une chaîne entourée de guillemets ?

Pour cela, rien de plus simple : il vous suffit de mettre le nom de l’étiquette entre crochets pour accéder à la valeur stockée à cet endroit. Et vous pouvez utiliser cette expression à n’importe quel endroit où vous utiliseriez un registre. Voyez vous-même comme c’est simple !

Je pinaille probablement, mais le code du dessus me gêne un peu, parce qu'il utilise des étiquettes inutiles. Le lecteur pourrait se demander à quoi servent celles autres que mon_argent et peut-être faire des suppositions erronées. Un réflexe pourrait par exemple être de considérer les blocs comme des fonctions. Mais je vais peut-être un peu loin. ^^

À section constante

Vous aurez à présent moins de mal à comprendre comment fonctionne notre appel système servant à écrire un texte dans la console (ici dans sa version Linux).

Peut-être serait-il plus propre, dans le code, de définir des constantes ? :)

Cet appel système prend quatre arguments.

Dans la mesure où le cours est également destiné à des débutants en programmation, peut-être que le terme "paramètres" est plus approprié ?

Ainsi, chaque fois que vous appellerez cette constante en utilisant son étiquette quelque part dans le code, cette étiquette sera remplacée par le résultat du calcul.

C'est marrant, j'aurais plutôt dit qu'on définit une fonction du coup.

Si j’ai bien compris ton tutoriel, le _start: de la ligne 9 est une étiquette ?

C’est quoi le petit , 10 à la fin de ton texte ?

Il me semble intéressant de rappeler le code, ou du moins la partie concernée. Actuellement, il me semble qu'il faut retourner au premier chapitre pour l'avoir sous les yeux.

Pour plus de clarté, on pourrait définir un synonyme NVL (pour « NouVelle Ligne ») au moyen de la directive %define.

Suis-tu une logique particulière pour la langue (français ou anglais) ? Tu as ici NVL, en-dessous END_STR, plus haut mon_argent, EXIT_SUCCESS.

Merci pour ce beau tutoriel. :)


  1. Pardon, j'arrête. 

+2 -0

Totalement d'accord avec Vayel sur la remarque de l'ambiguité, sur le coup je me suis dit qu'il s'agit du code personnel, puis en voyant marqué syscall plus bas je me suis dit que peut être pas, sans être certain.
Sinon j'ai lu l'introduction sur téléphone donc ca fausse peut être les choses mais j'ai trouvé ça vachement dense.

+0 -0

Et bam, il a encore frappé !

Je sais que tu t’ennuies, si je n’écris pas assez souvent. :-P

J'aurais juré qu'il existe un nom plus court pour parler de ça.

Quel surprenant hasard… *hurk hurk hurk*

Tu n'avais pas trop détaillé cette notion de "bas-niveau" ou "proche de la machine" dans le tutoriel sur les bases de la programmation et je crois que ça pose souci pour comprendre ce passage. On peut s'en passer je pense, mais peut-être pourrais-tu, maintenant que tu as un peu parlé des bits et des instructions, détailler la notion ? J'avoue ignorer comment tu pourrais faire ça de manière pas trop lourde. :(

Celui-là est passé entre les mailles du filet : en reprenant le cours, j’ai remplacé toutes les mentions de « langage de haut niveau » par « langage plus évolué », comme ça, ça reste vague. Et j’ai reformulé concernant le « proche de la machine ».

Pourquoi se baserait-on sur les documents de référene d'Intel ? :)

Parce que, comme je le dis un peu plus haut, c’est eux qui ont créé l’architecture x86 et qui construisent la plupart des processeurs de cette famille. Donc c’est the seule et unique référence faisant autorité. ^^

Il faudrait que je relise à tête reposé mais, sur le coup, je m'emmêle les pinceaux entre x86 vs ARM, syntaxe (Intel vs AT&T), directives (NASM/MASM…) et instructions, propres à chaque fabricant.

Ouais, faut se le mettre dans la tête, et après, ça va mieux.

J'ai un peu bogué là-dessus, croyant que tu nous forçais à lire ton cours. :P "sachez que vous devrez malgré tout lire la partie sur x84" me semble plus clair. Mais c'est un détail.

Bien sûr que je vous force à continuer à le lire !! Tu commences, tu finis, c’est comme à la cantine ! è_é

:-P

J'avais hésité en lisant le passage sur les préfixes des valeurs immédiates numériques mais là je pense que maîtriser la notion de base (décimale, hexadécimale…) devrait être un pré-requis. :)

Bien vu. :)

On pourrait se demander si 128 bits suffisent. Peut-être compléter la phrase avec un truc du genre : "128 bits, ce qui suffit, je vous laisse vous en convaincre, à conserver toute l'information". ^^

Nan, là, c’est un peu abusé. Si je dis que 128 bits suffisent et que mon lecteur n’est pas convaincu, il se débrouille pour se rendre compte que ça marche…

Je ne suis pas un expert en pédagogie, aussi je me demande s'il est judicieux de mélanger bonnes et mauvaises pratiques.

Ce ne sont pas des bonnes et mauvaises pratiques, mais des choses qui compilent et d’autres non. J’explique en dessous ce qui marche et ce qui ne marche pas, mais j’ai pensé que ce serait plus clair avec un exemple pour illustrer.

Peut-être ajouter une note pour dire qu'on a le même problème avec un guillemet dans une chaîne entourée de guillemets ?

J’en ai profité pour parler des chaînes entre ` dont j’ignorais l’existence quand j’ai écrit la première version du cours.

Je pinaille probablement, mais le code du dessus me gêne un peu, parce qu'il utilise des étiquettes inutiles. Le lecteur pourrait se demander à quoi servent celles autres que mon_argent et peut-être faire des suppositions erronées. Un réflexe pourrait par exemple être de considérer les blocs comme des fonctions. Mais je vais peut-être un peu loin. ^^

Ouep.

D’autant que c’est exactement comme ça qu’on créée des fonctions en assembleur, il manque juste l’instruction ret à la fin. ^^

Peut-être serait-il plus propre, dans le code, de définir des constantes ? :)

Le truc, c’est que je n’introduis les noms SYS_WRITE et STDOUT que dans les paragraphes qui suivent, et que faire l’inverse n’aurait pas de sens.

C'est marrant, j'aurais plutôt dit qu'on définit une fonction du coup.

Vraiment pas. Le calcul est fait à la compilation, seul le résultat est intégré dans le code machine généré.

Il me semble intéressant de rappeler le code, ou du moins la partie concernée. Actuellement, il me semble qu'il faut retourner au premier chapitre pour l'avoir sous les yeux.

Techniquement, il suffit de remonter une section plus haut, mais j’ai mis un lien pour être totalement paré.

Suis-tu une logique particulière pour la langue (français ou anglais) ? Tu as ici NVL, en-dessous END_STR, plus haut mon_argent, EXIT_SUCCESS.

Pas de manière très stricte. En gros, tout ce qui correspond à des noms standards sera en anglais (comme EXIT_SUCCESS ou STDOUT), et ce qui correspond à des noms créées par le programmeur sera en français. Mais parfois, ça peut être chiant, alors je donne plutôt un nom anglais, comme dans le cas de END_STR, où FIN_CHAI n’aurait pas été très parlant…

Après, je peux régulariser, c’est pas gênant.

Merci pour ce beau tutoriel. :)

C’est toujours un plaisir. :)

+0 -0

C'est marrant, j'aurais plutôt dit qu'on définit une fonction du coup.

Vraiment pas. Le calcul est fait à la compilation, seul le résultat est intégré dans le code machine généré.

Ah, je n'avais pas compris ça. Je croyais qu'il calculait la valeur à chaque fois qu'il rencontrait l'étiquette.

Rien à dire sur les autres réponses, merci pour ton retour. :)

+0 -0

Suite aux remarques de Vayel, je mets en bêta une version revue et corrigée, que vous pouvez dès à présent lire.


Et histoire de vous faire saliver, voici comment va s’organiser la suite du cours.

Chapitre 5 Les registres de plus petite taille (eax, di, r8b, etc.), ainsi qu’un certain nombre d’instructions généralistes, mathématiques et de manipulation de la mémoire, faisant pour une partie d’entre elles intervenir ces fameux registres plus petits.

Chapitre 6 Le registre RFLAGS et son fonctionnement. Des instructions directement liées à ce registre (comme stc, ou encore cmp), et d’autres instructions mathématiques et de manipulation de la mémoire, qui avaient besoin de RFLAGS pour être comprises.

Chapitre 7 Les sauts. Les instructions bit à bit.

Chapitre 8 Le fonctionnement de la pile et les instructions liées. Les autres types de mémoire (variables non initialisées et données en lecture seule). Les préfixes rep et lock.

Chapitre 9 Les fonctions et les instructions liées. Comment utiliser des fonctions C depuis l’assembleur, ce qui permet d’expliquer les appels système de Windows.

Chapitre 10 Un nouveau TP, sur un sujet encore à définir.


La question qui se pose, c’est que faire après ? Pour résumer, voici les aspects qui restent à traiter, dans les grandes lignes.

  • L’utilisation de nombres à virgule et les (très (trop)) nombreuses instructions SIMD, c’est à dire les extensions MMX, 3DNow!, les différentes générations de SSE, etc.
  • Aller plus avant dans l’utilisation des appels système.
  • Le mode protégé, qui n’a quasiment aucune différence avec le mode long dans le cadre d’un OS (mais beaucoup plus si l’on se passe d’OS).
  • Le mode réel, nettement différent mais inutilisable au sein d’un OS récent, et le BIOS.
  • Quelques instructions plus rares, comme les instructions liées à AES, ou les instructions bit à bit de la série BMI/TBM, introduites en 2012-2013.

Ce que je me demande, c’est s’il ne serait pas plus judicieux d’adopter un fonctionnement similaire à celui de la série de tutos Python.

Après le deuxième TP mentionné plus haut, on aurait encore quelques chapitres sur l’utilisation des appels système et de la bibliothèque standard du C, avec éventuellement quelques directives supplémentaires de NASM (comme la directive %macro, qui peut être très puissante), et un dernier TP sur quelque chose d’un peu costaud.

Éventuellement une annexe sur la manière de faire des appels système / utiliser une fonction C depuis un OS 32 bits, parce que c’est beaucoup moins normalisé que dans les OS 64 bits, et le cours d’introduction à l’assembleur serait terminé.

Il y aurait alors plusieurs cours qui se baseraient sur celui-là et seraient relativement indépendants les uns des autres. Un cours sur la FPU et les instructions SIMD, déjà. Un tuto assez court sur les instructions avancées mentionnées au 5e point plus haut.

Un cours sur l’assembleur sans OS, qui aborderait le mode réel, le mode protégé et comment passer en mode long. Et puis un cours sur le BIOS, qui pourrait être intégré à celui sur le mode réel, ou bien constituer un cours à part, à voir. De toute façon, j’ai hérité du cours de Mewtow sur le BIOS, donc je peux en faire ce que je veux.

Alors voilà, qu’en dites-vous ? Pensez-vous que ce soit une bonne idée ? Avez-vous des remarques ?

+2 -0

Promis, je ne t'oublie pas. :)

J'espère pouvoir dégager du temps pour me rafraichir la mémoire en reprenant depuis le début, l'objectif étant de te faire un retour correct sur le TP.

Concernant tes questions, je n'ai malheureusement pas le recul nécessaire pour y répondre.

+2 -0

Salut,

Juste pour dire, le code proposé pour OpenBSD n'est pas à jour par rapport à notre discussion par m.p. Il est nécessaire d'ajouter la fameuse section .note et d'employer l'option -nopie de ld pour que cela fonctionne (l'option -static est a priori inutile). Ce qui nous donne donc le code suivant.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
global _start

section .note
        align   2
        dd      8,4,1
        db      "OpenBSD",0
        dd      0
        align   2

section .data
    texte db 'Je suis la voix de ta machine !', 10
    taille equ $ - texte

section .text

_start:
    mov rax, 4
    mov rdi, 1
    mov rsi, texte
    mov rdx, taille
    syscall

    mov rax, 1
    mov rdi, 0
    syscall
+0 -0

La question qui se pose, c’est que faire après ? Pour résumer, voici les aspects qui restent à traiter, dans les grandes lignes.

Dominus Carnufex

L'idée d'une collection d'articles me paraît adéquate. Finalement, certains sujets comme le mode réel ou le BIOS n'ont sans doute pas leur place dans un tuto d'introduction s'agissant de notions plus avancées. De même, je pense que les instructions spécifiques comme celles liées au chiffrement ou les instructions vectorielles auraient également leur place dans des écrits à part.

En revanche, je suis d'avis que les instructions x87 et quelques unes des instructions SSE relativent à la manipulation des nombres flottants pourraient être présentées dans cette introduction. Aussi, pourquoi ne pas toucher un mot du mode protégé étant donné qu'un certains nombres de PC tournent aujourd'hui encore dans ce mode ?

+1 -0

Introduction

Et tout état de cause, si vous pensez ne pas être totalement au fait

"En tout état de cause" ?

En deuxième lieu, ce cours n’est pas un cours d’architecture des ordinateurs : contrairement à ce qui se fait ailleurs, vous n’y trouverez pas dès les premiers chapitres une explication détaillée du matériel qui se cache derrière les instructions assembleur. On cherche plutôt à vous rendre dès que possible capables de programmer par vous-mêmes, et d’observer le résultat de votre travail.

En relisant la première section du premier chapitre, je me suis demandé si posséder une connaissance globale du fonctionnement d'un ordinateur ne devait pas être un pré-requis. Tu démystifies un peu la chose dans le cours d'introduction à la programmation, mais pas suffisamment je pense (par exemple, le terme "bit" n'apparaît pas).

Avoir des bases dans l’utilisation de la ligne de commande. Comprendre ce que sont les bases numériques.

Il manque un retour à la ligne. :)

Première approche de l’assembleur

L’assembleur, qu’es acò ?

Lorsque des instructions étaient ajoutées au processeur, des instructions étaient ajoutées au langage d’assemblage. Lorsqu’un nouveau mode de fonctionnement était ajouté au processeur

C'est un détail, mais il y a beaucoup de "ajouté". ^^

Comment on code en assembleur

La première, c’est qu’il existe deux manière d’écrire le langage assembleur

"manières"

En résumé, dans ce cours, nous allons étudier l’assembleur x86 avec NASM.

Et syntaxe Intel. :)

Premier exemple plein d’originalité

Voilà, l’édition de liens est faite !

Le lecteur pourrait peut-être se demander à quoi ça sert d'éditer les liens si on n'a qu'un seul fichier. J'ignore si tu peux répondre facilement à cette question.

Merci !

+0 -0

Changeons de registre

RAS chef !

Pour une poignée de directives

Système ! SYSTÈME !!

elles sont donc particulièrement utilisées pour définir des synonymes

NASM ne propose pas des constantes toutes prêtes, couramment utilisées ?

%else ; Si on est sous Windows, pas de définition.

Ce else vide ne risque-t-il pas de faire croire au lecteur débutant qu'il est nécessaire d'en mettre un, même si on ne fait rien ?

Label Hélène de Troie

Il y a ici à la fois des formes correctes et des formes fautives. Voyons un peu cela.

Honnêtement, j'ai survolé la liste, et me suis contenté de retenir "À titre personnel, …".

add [mon_argent], 12000

Que se passe-t-il si mon argent dépasse quatre octets ?

À section constante

Une constante est constituée d’une étiquette, de la directive equ et d’une expression, c’est-à-dire d’un calcul simple que NASM va faire à notre place. Ainsi, chaque fois que vous appellerez cette constante en utilisant son étiquette quelque part dans le code, cette étiquette sera remplacée par le résultat du calcul. Par exemple, les deux codes suivants sont équivalents.

Je m'emporte peut-être, mais le lecteur pourrait confondre avec :

Notez bien que vous devez lui fournir une adresse en mémoire où se trouve le texte, et non le texte lui-même. C’est pourquoi il vous faut écrire l’étiquette seule sans crochets autour.

Du coup, peut-être serait-il plus clair de commencer par écrire la taille en dur, puis d'introduire la notion de constante, en indiquant que texte et taille ne représentent à priori pas la même chose. Tu le mentionnes d'ailleurs plus bas : "Notez bien que dans le cas précis des constantes et uniquement celui-ci, le nom de l’étiquette ne doit surtout pas être placé entre crochets, puisque l’étiquette équivaut à une valeur et non à l’adresse de cette valeur.".

Mais ce n’est pas toujours une bonne idée de faire le calcul vous-même.

Tu pourrais également mentionner l'intérêt sémantique, comme tu l'as fait pour %define : taille_chaine est plus explicite que 15.

TP

Le sujet est très intéressant. Par contre, le bloc de consignes est un peu indigeste. Tu pourrais le rendre plus lisible en ajoutant des titres. ^^

Seulement, il y a un hic. Après une première division, RDX contiendra le caractère correspondant au chiffre des unités. Oui, mais stocké sur huit octets (64 bits).

Il me semble intéressant d'illustrer ce problème et sa solution (le tampon) par un exemple.

Encore merci pour ce contenu de qualité.

+0 -0
Ce sujet est verrouillé.