TUTORIAL ASSEMBLEUR - chapitre 6 -------------------------------- La mémoire ---------- La mémoire et ses instructions ------------------------------ J'ai déjà écrit une introduction sur la mémoire de l'ordinateur dans la leçon 1, mais nous allons aborder sa mise en place et voir d'une façon plus précise, la manière de l'utiliser. Attention : nous travaillons pour l'instant en mode réel, le code protegé demande du code différent. Il existe pour cela plusieurs instructions. Nous avons vu que "MOV SI, offset MESSAGE" plaçait dans SI, la valeur de l'offset de MESSAGE. Pour une donnée dans un autre segment, il faut aussi utiliser le "MOV AX,seg MESSAGE" et ensuite "MOV DS,AX". En effet, les registres ES, DS, FS et GS n'acceptent pas de valeur numérique directe mais seulement des registres. Il existe une autre instruction, LEA, qui permet de placer l'offset dans un registre mais en plus court. Par exemple "LEA SI,MESSAGE" placera dans SI, l'offset de Message. Privilégiez l'emploi de LEA plutôt que du MOV. Cela rend le code plus clair et plus compact. Pour pouvoir déplacer des blocs entiers de mémoire, nous n'allons pas lire chaque octet et le placer dans l'autre bloc mais nous employerons les instructions : MOVSB MOVSW MOVSD La première pour déplacer une (B)ytes, la deuxième un (W)ord et la dernière pour déplacer un (D)words qui font 32 bits. Ces instructions demandent que la source (DS:SI) et l'arrivée (ES:DI) soient configurées. Il ne faut pas diriger les données vers n'importe quel emplacement de la mémoire. Vous planteriez à coup sur le programme. Nous verrons plus loin, comment allouer des blocs de mémoire. Par exemple dans DS:SI, nous pouvons avoir les données d'une image et dans ES:DI, l'adresse de la mémoire video (A000h:0000). Si nous voulons copier 10000 bytes, nous employerons directement le MOVSD (si nous travaillons avec un 386 ou plus) ou avec MOVSW. Pour plusieurs MOVSx, il est inutile de faire une boucle. L'instruction REP est là pour cela. Il faut utiliser conjointement avec REP, le registre CX qui contient le nombre d'itérations (le nombre de fois que l'on répete le MOVSx). Pour les 10000 bytes, nous avons : MOV CX,10000 REP MOVSB Si nous utilisons les Words (plus rapide), c'est : MOV CX,5000 (un word=2 bytes) REP MOVSW Finalement, avec le 32 bits, c'est : MOV ECX,2500 (un dword=2 words=4 bytes) - utilisation d'un registre étendu REP MOVSD A chaque MOVSx, DI augmente de 1,2 ou 4 bytes. Maintenant, si nous voulons garder des données ou les placer dans un emplacement de la mémoire ? Nous utiliserons les instructions : STOSB STOSW STOSD Comme pour les MOVSx, cette instruction stocke un byte, un word et un dword. A la différence des déplacements, les STOSx utilisent AL, AX (EAX 32bits) comme valeur à stocker. La valeur de AL,AX,EAX sera stockée dans ES:DI. A chaque STOSx, DI est augmenté de 1,2 ou 4 bytes. Ces instructions sont utiles pour effacer l'écran par exemple ou remplir un bloc mémoire avec la même valeur. MOV CX,1000 MOV AX,0 REP STOSB Dans cette exemple, CX équivaut à 1000, pour 1000 répétitions. Ensuite, le MOV AX,0 qui est la valeur qui sera placée dans le bloc mémoire. Pour finir, le REP STOSB qui dit que nous plaçons 10000 bytes de valeur 0 à l'emplacement de ES:DI. En fait, ici nous placons AL, on ne tient pas compte de AH dans un STOSB. Pour réserver de la mémoire, il faut employer les interruptions, ici nous restons dans la mémoire conventionnelle, c'est à dire que l'on ne dépasse pas les 640ko attribués par le DOS. Si l'on veut plus de mémoire, il faut utiliser les modes dits protégés ou flat. La programmation de ces modes est différentes et il faut avoir quelques notions sur le DOS et la gestion de la mémoire. Si vous voulez dès maintenant en savoir plus, lisez des documentations comme celles d'Intel. Pour la mémoire conventionnelle, on doit d'abord libérer l'emplacement occupé par notre programme : MOV BX,taille ; la taille=(taille du prog en octet / 16)+1 MOV AH,04ah INT 21h Ici, taille=4096 correspond 64ko. Ajustez donc la taille en fonction de votre programme. J'ai ajouté 1 à la taille pour éviter des erreurs (normalement pas nécessaire, on ne sait jamais ;). Ensuite, il faut réserver le bloc de mémoire: MOV AH,48h MOV BX,mem_voulue ; (mem_voulue=memoire_desiree/16)+1)) INT 21h JC NOT_ENOUGH_MEM La mémoire voulue se calcule comme pour la libération de la mémoire. Le JC NOT_ENOUGH_MEMORY est utile pour détecter les erreurs. Si la mémoire n'est pas disponible, votre programme ira au label NOT_.... et fera ce que vous voulez pour indiquer l'erreur (affichage d'un texte, retour au DOS). IMPORTANT, il faut conserver la valeur de AX après avoir exécuté le INT 21h. AX contient le segment du bloc alloué et il faut garder cette valeur pour pouvoir la réutiliser lors du désallouage. Finalement, il faut désallouer les blocs de mémoire APRES les avoir utilisé (sinon quel intérêt ?). MOV BX,4096 ; (taille du bloc) MOV AX,segment_bloc ; (le segment du bloc, nous l'avons précieusement gardé) MOV ES,AX MOV AH,49h INT 21h Le fait de ne pas désallouer de la mémoire va vous en enlever pour des programmes qui seraient exécutés par la suite. ### Chapitre 6 - dake / c a l o d o x ### ### http://www.space.ch/scene/calodox ###