2017-07-22 7 views
1

Ma tâche consiste à concevoir une procédure enfant de division dword (divdw) qui ne débordera pas dans l'assembly 8086 (j'utilise masm5.0/masm.exe et masm5.0/link.exe et debug.exe dans MS-DOS). AX, CX, et DX sont utilisés pour enregistrer le résultat de divdw. Le code suivant ne peut pas encore être exécuté.Dans l'assembly 8086, comment utiliser la pile dans une procédure enfant?

Voici la tâche:

entrée:

(ax) = faible 16 bits d'un dividende dword
(dx) = haute 16 bits d'un dividende dword
(cx) = 16 bits diviseur

sortie:

(ax) = faible 16 bits du résultat
(dx) = haute 16 bits du résultat
(cx) = reste

La formule I utilisé à calco divdw:

dividende/diviseur = quot (haute 16 bits du dividende/diviseur) +
(rem (haute 16 bits du dividende/diviseur) * 2^16 + faible 16 bits du dividende)/diviseur

Voici mon code:

assume cs:code 

     code segment 
start: mov ax,4240h 
     mov dx,000fh 
     mov cx,0ah 
     call divdw 
     mov ax,4c00h 
     int 21h 

divdw: push bx 
     push dx     ;ss:[0ch] 

     mov ax,dx 
     mov dx,0 
     div cx 
     mov ax,0    ;rem, only need dx 
     mov bx,ss:[0ch] 
     div bx 

     ;; finish 1 
     push dx 
     push ax 

     ;; get dx, into ax 
     mov ax,ss:[0ch] 
     div cx 
     ;; finish 2 
     push ax 

     pop dx     ;ax after 2 
     pop ax     ;ax after 1 
     pop cx     ;dx after 1 

     ;; recover bx 
     pop bx 
     pop bx 
     ret 


     code ends 
     end start 

Dans ce code, je suis en train d'utiliser pop et push mais n'a pas défini un segment de pile. Est-ce permis? (Dans le débogueur, j'ai trouvé le SS:SP mais le push ne peut pas fonctionner correctement.)
Sinon, où dois-je définir la pile et comment l'utiliser?

Si je définis un segment de pile dans la procédure principale, il semble que je doive enregistrer les valeurs SS et SP au début de la procédure, mais où dois-je les enregistrer? Puis-je les sauvegarder dans la pile, ou dois-je les sauvegarder quelque part en mémoire?

La procédure de départ est donnée aux fins du test.

Merci!


Modifier:

Merci à vous deux! Avec votre aide, j'ai terminé cette tâche.Le code est maintenant comme suit:

assume cs:code,ss:stack 

     stack segment 
     dw 8 dup (0) 
     stack ends 

     code segment 
start: 
     mov ax,stack 
     mov ss,ax 
     mov sp,16 

     mov ax,4240h 
     mov dx,000fh 
     mov cx,0ah 
     call divdw 
     mov ax,4c00h 
     int 21h 

divdw: push bx 
     push dx     ;ss:[0ah] 
     push ax     ;ss:[08h] 

     mov ax,dx    ;ax=0fh 
     mov dx,0    ;dx=0 
     div cx     ;ax=1,dx=5 
     push ax     ;1, quot, should be dx when ret, as the high 16 bit of result 
     ;; use dx=5 and 4240h to do div 
     mov ax,ss:[08h]   ;ax=4240h. rem, only need dx of last result, use low 16bit of dividend, ie. ax, as ax 
     div cx     ;ax=86a0h,dx=0h 

     ;ax already is low 16bits of quot 
     mov cx,dx    ;rem, store in cx 
     pop dx     ;1, high 16 bits of quot 

     pop bx     ;discard original ax 
     pop bx     ;discard original dx 
     pop bx     ;recover original bx 
     ret 


     code ends 
     end start 

Modifié le 20170724

Pourtant, une autre version, se débarrasser de la SS: [08h], et utilisé un autre 3 registres pour stocker. Je ne suis pas sûr que ce soit mieux, mais ça fonctionne.

assume cs:code,ss:stack 

     stack segment 
     db 16 dup (0) 
     stack ends 

     code segment 
start: 
     mov ax,stack 
     mov ss,ax 
     mov sp,16 

     mov ax,4240h 
     mov dx,000fh 
     mov cx,0ah 
     call divdw 
     mov ax,4c00h 
     int 21h 

divdw: push bp 
     mov bp,sp 
     push si 
     push bx 
     push dx 
     push ax 
     mov si,sp 

     mov ax,dx    ;ax=0fh 
     mov dx,0    ;dx=0 
     div cx     ;ax=1,dx=5 
     push ax     ;1, quot, should be dx when ret, as the high 16 bit of result 
     ;; use dx=5 and 4240h to do div 
     mov ax,ss:[si]   ;ax=4240h. rem, only need dx of last result, use low 16bit of dividend, ie. ax, as ax 
     div cx     ;ax=86a0h,dx=0h 

     ;ax already is low 16bits of quot 
     mov cx,dx    ;rem, store in cx 
     pop dx     ;1, high 16 bits of quot 

     pop bx     ;discard original ax 
     pop bx     ;discard original dx 
     pop bx     ;recover original bx 
     pop si 
     mov sp,bp 
     pop bp 
     ret 


     code ends 
     end start 
+0

Comment est-ce chargé/lié? La pile doit être préparée par le chargeur –

+0

J'utilise masm5.0/masm.exe et masm5.0/link.exe et debug.exe sous MS-DOS. – cmal

+1

Une pile de seulement 16 octets? Vous devez plaisanter! – Fifoernik

Répondre

3

Vous ne devez pas les enregistrer tant que le nombre de PUSH est égal au nombre de POP.

Ce n'est pas toujours pratique, mais c'est votre cas, ça devrait aller. À l'exception de la valeur DX sauvegardée, la valeur enregistrée est à la fin, ce qui peut poser problème.

EDIT:

Je ne vois pas que vous en avez besoin dans ce cas, mais en général, vous pouvez le faire pour restaurer BP et SP:

push bp ; first statement of subroutine 
mov bp, sp 

... 

mov sp, bp 
pop bp 
ret 

Au sein de votre sous-programme, vous avez alors BP à utiliser comme adresse de base pour tous les paramètres placés sur la pile avant l'appel. Encore une fois, votre exemple ne montre pas, mais vous ne semblent pas aussi d'utiliser la valeur que vous mettez dans AX registre et la déclaration

mov bx, ss:[0ch] 

est un peu déroutant. Comment savez-vous ce qu'il y a à cette adresse?

+0

FYI BP est le registre de pile de sauvegarde. mov bp, sp –

+0

Oui, j'ai seulement besoin de sauvegarder bx; ax, cx, dx sont utilisés pour enregistrer le résultat de divdw. – cmal

+0

Ahh, merci pour ça. Dois-je utiliser mov bp, sp dans l'enfant ou la procédure principale? Si dans la procédure de l'enfant, devrais-je sauvegarder d'abord bp? Ma tâche consiste à concevoir une procédure divdw enfant. – cmal

3

Sinon, où dois-je définir la pile et comment l'utiliser?

La façon dont vous définissez le segment de pile dépend du programme de l'assembleur. Sorte de segment stack et/ou assume ss:stack. Il n'est pas nécessaire de modifier SS:SP directement au démarrage, sauf les programmes .com/model tiny.

Il semble que je doive enregistrer les valeurs ss et sp au début de la procédure, mais où dois-je les enregistrer?

Le programme type utilise uniquement un segment de pile unique, il n'est donc pas nécessaire de sauvegarder/modifier le registre SS. En ce qui concerne SP, non, vous ne pouvez évidemment pas (ne devrait pas) l'enregistrer sur la pile. L'astuce habituelle est:

push bp 
mov bp, sp 
... ; use [bp+4] to address the first argument on the stack 
.... ; ss segment is assumed by default when [bp] used 
mov sp, bp ; if sp was modified by some push/sub instructions 
pop bp 
ret 

Cependant, il est utile que si vous avez vraiment besoin de travailler avec les args stack à l'intérieur de la procédure. Sinon, utilisez simplement push/pop si nécessaire.

+0

Merci @Matt. Le 'supposez ss: pile' aide vraiment. Je vais continuer mon étude et voir ce que veut dire '.com/model tiny'. – cmal

+0

Désolé pour mon erreur! Je ne peux pas croire que j'ai écrit ce remplacement idiot 'SS: IP'. Excuses. – Fifoernik