Logique d'utilisation du registre DS (mode réel)

Résolu
powel42 Messages postés 8 Date d'inscription vendredi 19 mars 2010 Statut Membre Dernière intervention 27 mars 2010 - 19 mars 2010 à 16:28
powel42 Messages postés 8 Date d'inscription vendredi 19 mars 2010 Statut Membre Dernière intervention 27 mars 2010 - 27 mars 2010 à 16:27
Bonjour à tous,

je suis curieux de savoir quelle est la "bonne" manière d'utiliser le segment DS (s'il y en a une).

Lorsque l'on démarre sous DOS 16 bits donc en mode réel un programme assembleur .COM, le registre DS (ainsi que ES, SS) ont la même valeur que CS

Je trouve ça pas normal étant donné qu'il faut systématiquement donner une autre valeur à DS que celle qui est donnée par défaut pour éviter d'écrire des données dans le code.

Et d'ailleurs ES aurai pu être initialisé pour pointer après la pile. Ainsi on aurai des données statiques dans DS et des données "dynamiques" pour les gros blocs de mémoire dans le tas après la pile.


Alors quelle est la bonne méthode ?

faire pointer DS après la pile ?

mov dx, ss
add dx, 4096
mov ds, dx


ou bien faire pointer DS juste après le code, par exemple si le code fait 1024 octets :

mov dx, cs
add dx, 64
mov ds, dx



Merci pour vos éclaircissements.

17 réponses

cs_ghuysmans99 Messages postés 3982 Date d'inscription jeudi 14 juillet 2005 Statut Membre Dernière intervention 30 juin 2013 16
21 mars 2010 à 11:36
Un programme .COM est toujours organisé comme ceci : PSP (256 octets) / CODE / DATA / STACK. Si tu ne dois pas tout le temps accéder à la mémoire vidéo, fais-toi quelques fonctions qui y accéderont et rendront la main avec la même valeur dans les registres de segment que lors de leur appel. Exemple (devrait fonctionner) :
effaceEcran:
 push es
 push di
 push cx
  mov ax,0xB800
  mov es,ax
  xor di,di
  xor ax,ax
  mov cx,80*25
  rep stosw
 pop cx
 pop di
 pop es
ret

---
VB.NET is good ... VB6 is better
3
cs_ghuysmans99 Messages postés 3982 Date d'inscription jeudi 14 juillet 2005 Statut Membre Dernière intervention 30 juin 2013 16
26 mars 2010 à 19:00
Ce n'est pas NASM qui le veut, mais DOS et l'utilisation du mode réel. Dans ce mode, la mémoire n'est pas protégée. De plus, on n'accède jamais au données via mov [ds:0],ax. Les variables n'existent pas vraiment en assembleur, ce ne sont que des abstractions. Quand tu fais var db 0xFF, tu dis simplement au compilateur que quand il voit var dans le code, il doit le remplacer par son adresse en mémoire.

le segment DS est censé être non confondu avec CS ou SS
Lorsque DOS lance un .COM, CS=DS=ES. Si tu veux accéder à quelque chose comme la mémoire écran, il te suffit de les modifier en les ayant sauvegardés précédemment sur la pile.
---
VB.NET is good ... VB6 is better
3
cs_ghuysmans99 Messages postés 3982 Date d'inscription jeudi 14 juillet 2005 Statut Membre Dernière intervention 30 juin 2013 16
19 mars 2010 à 22:05
Je pense que tu te trompes : un .COM ne peut excéder 64Kio (adressage max. pour un registre 16 bits). Donc tu ne risques pas d'écraser ton code si tu fais :
org 0x100
[...]
mov word [ds:mavariable],0x12FF
[...]
int 0x20
mavariable dw 0

---
VB.NET is good ... VB6 is better
0
cs_patatalo Messages postés 1466 Date d'inscription vendredi 2 janvier 2004 Statut Modérateur Dernière intervention 14 février 2014 2
20 mars 2010 à 03:12
salut,


De toute manière, en mode réel, tu n'as pas réellement de distinction entre les types de données. C'est réservé au mode protégé.

En mode réel, un segment aura toujours acces a sa valeur de base + 64ko.

Un .com est normalement limité a 64ko mais rien ne t'empêche d'allouer de la mémoire ou d'acceder a n'importe quelle zone en dessous des 1Mo.

Il est plus dangereux de changer tes registres de segment que de les laisser CS=DS=ES=SS car tu pourrait ecraser les données des autres programmes ou du DOS plutôt que celles de ton propre programme. Le résultat pourrait être catastrophique.

@++
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
powel42 Messages postés 8 Date d'inscription vendredi 19 mars 2010 Statut Membre Dernière intervention 27 mars 2010
20 mars 2010 à 17:29
Merci pour vos réponses,

en gros si j'ai bien compris, un fichier .COM a été concû pour travailler code et données dans un segment de 64 K.
Autrement dit les registres CS, DS, ES, SS n'existaient peut être pas lorsque la norme .COM a été mis au point.

C'est lors de l'apparition du .EXE que les registres CS, DS, ES et SS ont pris tous leurs sens ?
0
cs_ghuysmans99 Messages postés 3982 Date d'inscription jeudi 14 juillet 2005 Statut Membre Dernière intervention 30 juin 2013 16
20 mars 2010 à 23:13
Les registres de segment existaient déjà et existe encore, mais il n'était pas nécessaire de les modifier. Si tu voulais faire un programme de plus de 64Kio, il te suffisait de faire un .EXE mais il valait alors mieux de le coder en un langage de plus haut niveau comme C ou Pascal.
---
VB.NET is good ... VB6 is better
0
powel42 Messages postés 8 Date d'inscription vendredi 19 mars 2010 Statut Membre Dernière intervention 27 mars 2010
21 mars 2010 à 00:12
Alors si ces registres existaient déjà ... c'est qu'ils sont là pour qu'on les changes à notre guise !

Il est plus dangereux de changer tes registres de segment que de les laisser CS=DS=ES=SS car tu pourrait ecraser les données des autres programmes ou du DOS plutôt que celles de ton propre programme. Le résultat pourrait être catastrophique.


C'est dangereux mais c'est fait pour ... si j'ai envie de copier une image dans la video RAM
C'est bien pratique de faire pointer DS:SI sur mon image en mémoire et faire pointer ES:DI sur un endroit de la video RAM
avec un REP MOVSB ça va tout seul

Donc ficher .COM ou pas ... il est "normal" de changer ces registres.

Maintenant j'en reviens à ma question du début du topic ... pourquoi en fait quand on démarre un fichier .COM on a CS=DS=ES=SS bêtement alors qu'il est évident qu'on ne va pas garder ces valeurs au long de notre programme ... d'ailleurs les vieux programmes DOS dont j'ai regardé le début ; ils changent systématiquement DS, ES et voir SS


ghuysmans99, tu m'a donné un exemple où tu utilise "org" pour signaler à l'assembleur d'où tu veux que ton programme commence pour effectivement pouvoir placer tes variables avant. Mais ça ne peut fonctionner que s'il y a une entête (exe header par exemple). Mais un fichier .COM pure, le programme est chargé systèmatiquement à partir du 257 ème octet du segment CS car les 256 premiers octets sont réservés au PSP.

Donc pas de possiblitée de placer des variables avant le programme, on est forcément obliger de les placer après ... et donc ma question : avant la pile ou après la pile ?

Donc si quelqu'un connait une logique connue dans l'affectation de DS ...
0
powel42 Messages postés 8 Date d'inscription vendredi 19 mars 2010 Statut Membre Dernière intervention 27 mars 2010
21 mars 2010 à 15:33
Voilà qui me semble plus familier, c'est à peu près ce que je fais sauf que je ne sauvegarde pas systématiquement ES, DI selon l'enchainement des appels fonctions.

PSP (256 octets) / CODE / DATA / STACK

Alors justement si j'ai ouvert ce topic c'est pour placer le segment DS au début de "DATA".
Histoire de ne plus me préoccuper de l'emplacement des données et de pouvoir écrire des choses genre :
mov byte ptr [0], variable0
mov byte ptr [1], variable1
mov word ptr [2], variable2
mov word ptr [4], variable3
...
...
etc ...

Alors y'a-t-il un moyen "standard" pour un executable .COM de connaitre son adresse de fin ; à partir de laquelle je pourrai définir DS ?

Merci.
0
cs_ghuysmans99 Messages postés 3982 Date d'inscription jeudi 14 juillet 2005 Statut Membre Dernière intervention 30 juin 2013 16
21 mars 2010 à 16:51
Vu qu'un .COM ne dépasse jamais 64Kio, tu fais simplement : mov ax,word [DS:tavariable]. Si c'est un tableau de mots, tu fais : mov ax,word [DS:tavariable+index*2]. Je ne vois pas où est ton problème !
---
VB.NET is good ... VB6 is better
0
powel42 Messages postés 8 Date d'inscription vendredi 19 mars 2010 Statut Membre Dernière intervention 27 mars 2010
21 mars 2010 à 22:20
J'aurai du être plus précis ; j'utilise DEBUG et l'assembleur du borland Pascal donc j'écris plutôt :

mov word ptr [2], 2000
..
..
..
inc word ptr [2]
..
..
..

jamais un nom de variable.

Quels assembleurs 8086 / 8088 je peux trouver produisant un .COM sans entête, ne rajoutant pas ni optmisant de code à ma place ?

Merci.
0
cs_ghuysmans99 Messages postés 3982 Date d'inscription jeudi 14 juillet 2005 Statut Membre Dernière intervention 30 juin 2013 16
22 mars 2010 à 20:30
TASM (fait par Borland) et NASM le font très bien. Perso, je préfère NASM : il n'y a pas d'en-têtes inutiles à ajouter en début du code source. Exemple de code source NASM :
org 0x100 ;fichier .com
mov ax,0x4C00
int 0x21

---
VB.NET is good ... VB6 is better
0
powel42 Messages postés 8 Date d'inscription vendredi 19 mars 2010 Statut Membre Dernière intervention 27 mars 2010
23 mars 2010 à 16:20
Ok Merci, je viens d'essayer NASM ... en fait on peut faire des "mavariable db 0" n'importe où dans le code ... c'est pourquoi les segments CS et DS peuvent et même doivent être confondus. Et lors de la compilation, NASM attribue les adresses au variables définies en y ajoutant la valeur de "ORG" ...

Donc on peut redéfinir des instructions en cours d'exécution, en tous càs ça a l'air d'être fait dans cet esprit ?

Est-ce que tu te sers souvent de la redéfinition du code et est-ce qu'il existe des techniques connues de redéfinition du code qui optimisent vraiment la taille de l'exécutable ?

Si tu connais des liens je suis preneur,

Merci
0
cs_patatalo Messages postés 1466 Date d'inscription vendredi 2 janvier 2004 Statut Modérateur Dernière intervention 14 février 2014 2
23 mars 2010 à 22:41
re,


c'est simple, le .com à été crée pour faire ce que l'on appelle le mode FLAT.

suivant les instructions que tu utilise, il peut être necessaire de surcharger le segment. Tu n'as pas ce problème en mode FLAT.

par exemple
mov [bp+4],? utilisera le segment ss.
mov [si+4],? utilisera le segment ds.

si tu veux utiliser ds avec bp, tu fais
mov [ds:bp+4],?

d'où l'utilisation du mode FLAT.

@++
0
cs_patatalo Messages postés 1466 Date d'inscription vendredi 2 janvier 2004 Statut Modérateur Dernière intervention 14 février 2014 2
24 mars 2010 à 03:36
re,


pour redefinir un code, il faudrait que ton code soit mis en data pour redevenir code. Je ne vois pas comment tu vas t-y prendre pour gagner de la place avec ce principe.


en tout cas, vu ton projet, je te souhaite de bon plantages et des heures d'arrachage de cheveux ;-)

@++
0
cs_patatalo Messages postés 1466 Date d'inscription vendredi 2 janvier 2004 Statut Modérateur Dernière intervention 14 février 2014 2
24 mars 2010 à 03:38
au fait, tu as raison de choisir nasm, c'est le plus puissant et ouvert en assembleur à l'heure actuelle à mon avis.
0
powel42 Messages postés 8 Date d'inscription vendredi 19 mars 2010 Statut Membre Dernière intervention 27 mars 2010
26 mars 2010 à 18:29
Bonjour et merci pour les réponses,

concernant l'explication du mode "FLAT" en 64 K, oui je veux bien croire qu'avec des additions on a pas besoin de déplacer le segment DS et autre. ça d'accord. Mais il me paraissait logique que si Intel a crée un CS et DS c'est pour que tous deux soient séparés, histoire qu'on puisse accéder de manière "protégée" aux données, c'est à dire que si DS est placé après CS et bien on peut tranquillement taper :
mov [0], ax
mov word [2], 0xFFFF
mov [65535], al

sans avoir le souci que ça puisse écrire là où il faut pas (code ou pile). Donc ça me paraissait logique que lorsque DOS charge un .COM, comme il connait la taille du .COM + la taille du PSP il serai capable d'attribuer à DS et à SS le déplacement qu'il faut pour qu'en tapant mov [0], ax ou mov [65535], al et bien on ne fasse rien planter ... puisque ça concerne le segment DS et qu'il est censé être non confondu avec CS ou SS ... mais bon il en est autrement ...

je vois qu'avec NASM la logique de programmer voudrai que le programme puisse se modifier puisqu'on peut taper ce genre de choses :

; appel de la routine "store_datas" avec les valeurs par défaut
mov di, 0
call store_datas

; maintenant on veut que les valeurs soient stockées en sens inverse avec un pas de 128 au lieu de 256
; on change directement le sous-programme, pas besoin d'utiliser des registres, d'empiler ou autre
; puisque CS et DS sont confondus

mov [store_direction], 0xEF81 ; on change l'ADD originel en SUB
mov [store_step], 128 ; on change le saut 256 originel en 128
call store_datas

ret

; "store_datas" sub-routine
store_datas:
..
..
store_direction dw 0xC781 ; ADD DI,
store_step dw 0x0100 ; 256
..
..
ret


J'ai l'impression que le fait qu'on puisse définir des variables en plein milieu du code encourage ce genre de choses, c'est pourquoi je posais la question est-ce qu'il existe des techniques connues de "redéfinition du code"

Puisque NASM semble être fait dans ce sens
0
powel42 Messages postés 8 Date d'inscription vendredi 19 mars 2010 Statut Membre Dernière intervention 27 mars 2010
27 mars 2010 à 16:27
Oui OK je vois ;-) c'est vrai que finalement c'est le .COM de DOS qui impose ça.

Bon il m'a fallut deux pages pour y voir plus clair,

Merci
0
Rejoignez-nous