|
DEUXIEME PARTIE
PREMIER CONTACT AVEC LE LANGAGE ASSEMBLEUR |
|
Le programme suivant est un programme EXE qui fait exactement la même chose que l’exemple précédent.
Examinons-le ! Tout d’abord, la directive org 100h a disparu. En effet, lors de l’exécution, CS pointera vers notre segment de code et non pas vers le PSP. Il est donc inutile de décaler les offsets de 256. Remarquons que notre programme dispose de deux segments supplémentaires :
Notre directive “assume” devient donc : assume cs:code, ds:data, ss:pile Ainsi, le compilateur est informé que DS pointera vers le segment “data” et SS vers “pile”. Les deux lignes suivantes,
mov ax, data
servent à initialiser le registre DS. Celui-ci pointe vers le PSP au début du programme mais nous voulons le faire pointer vers notre segment de données appelé “data”. Cela est nécessaire puisque la fonction 9 de l’interruption 21h attend l’adresse de la chaîne dans le couple DS:DX et que notre message se trouve dans le segment de données. La première instruction charge l’adresse du segment “data” dans AX. La seconde transfère cette valeur de AX dans DS. Mais pourquoi diable utiliser AX comme intermédiaire ? Après tout, on pourrait écrire : mov ds, data Eh bien non ! Pour la simple raison que DS est un registre de segment et qu’en tant que tel on ne peut pas lui charger de valeur immédiate. On appelle « valeur immédiate » toute constante tapée directement dans l’instruction elle-même. Exemples de chargement de valeurs immédiates : mov ax, 135 ;charge 135 dans AX mov bx, offset message ;charge l’offset de message dans BX mov bx, offset fin – offset debut ;charge le nombre d’octets entre fin et debut dans BX mov es, 10 ;instruction illicite car ES est un registre de segment ! Remarque : une autre possibilité aurait été d'écrire : “PUSH AX” (empiler AX) puis “POP DS” (dépiler le dernier nombre empilé et le placer dans DS). Les trois lignes suivantes :
mov ah, 09h
n’ont pas changé. Il nous faut également terminer le programme par un appel de la fonction 4ch de l’interruption 21h. C’est ainsi que se terminent les programmes EXE.
mov ah, 4ch
Remarque : on aurait également pu écrire :
mov ax, 4c00h
La seule différence est que AL est mis à zéro, ce qui indique au programme à qui on rend le contrôle (ici le DOS) que notre programme s’est terminé normalement. Les fichiers COM peuvent également utiliser la fonction 4ch. Le segment de code se termine : code ends et le segment de données commence à sa suite : data segment use16 message db “Bonjour, monde !”, ‘$’ data ends Il nous reste à écrire le segment de pile. Dans ce programme, il n’était pas absolument indispensable de le séparer du segment de code. Mais c’est une bonne habitude de le faire. pile segment stack remplissage db 256 DUP (?) pile ends Le mot-clé “stack” indique que ce segment est le segment de pile. Les mots “db 256 DUP (?)” déclarent 256 octets non initialisés. C’est la « matière » de notre pile. Sachez que tout appel d’interruption se traduit par l’empilage des flags et de CS:IP. Il est donc indispensable d’avoir une pile, même si celle-ci peut éventuellement partager le même segment que le code, comme dans un fichier COM. Mais dans un programme EXE, il vaut mieux réserver un segment à la pile. Les 256 octets que nous déclarons ici indiquent seulement que la pile contient 256 octets. Ainsi, au début de l’exécution, SS:SP pointera vers la fin de ces octets. Nous verrons ce que signifie le point d’interrogation dans la troisième partie. La fin du fichier et le point d’entrée sont signalés par : end debut Et voilà ! Vous avez découvert l’allure d’un programme en assembleur. Nous pouvons donc à présent nous pencher sur l’étude du langage.
|
Copyright © 2000-2012 - www.developpez.com