2017-11-03 12 views
0

Hallo ich möchte Prozedur, die Summe zwei Zahlen aus dem Bildschirm in emu8086 eingegeben, ich mag das Programm, um nach dem Vorgang zu beenden Ich rufe die Prozedur sumUp und es tut es gut, aber nach ret in der Prozedur das Programm beendet .. ich möchte das Programm unten den Coderuf SUMUP weiterhin Danke sehr vielWarum wird das Programm nicht fortgesetzt, nachdem der Vorgang abgeschlossen ist (emu8086)?

; multi-segment executable file template. 

data segment 
    message1 db "Enter 2 number..$" 

    num1 db 0 
    num2 db 0   
    suma dw 0 

ends 

stack segment 
    dw 128 dup(0) 
ends 

code segment 

    sumUp proc 

     pop bx 
     pop ax 
     sub ax,30h 

     mov suma,ax 
     pop ax  
     sub ax,30h 
     add suma,ax 

    ret 
    sumUP endp 


start: 
; set segment registers: 
    mov ax, data 
    mov ds, ax 
    mov es, ax 

; add your code here 

    lea dx,message1 
    mov ah,09h 
    int 21h 

    mov ah,1h 
    int 21h 

    mov num1,al 

    mov ah,1h 
    int 21h 

    mov num2,al 

    mov dh,0d 
    mov dl,num1 
    push dx 

    mov dh,0d 
    mov dl,num2 
    push dx 

    call sumUp  
    //I want the program to continue here after procedure is finished 

    **mov cx,0** 



ends 

end start ; set entry point and stop the assembler. 
+2

Die 'ret'-Anweisung kehrt nicht aus der Prozedur zurück. Er öffnet die Rücksprungadresse vom Stack und springt dorthin. Du hast es verloren, indem du 'pop bx' zu Beginn von' sumUp' gemacht hast, die Return-Adresse in 'bx' geladen hast, und du hast es nicht zurückgespeichert, so dass das' ret' komplett andere Werte aus dem Stack herausspringt. Die CPU versteht nichts über Prozeduren, die 'call/ret'-Befehle ahmen dies durch Verwendung von Stapelspeicher nach, aber sie funktionieren nur so lange, wie Sie die Struktur des Stapels korrekt halten. – Ped7g

+0

Und der gebräuchlichere Weg, Argumente in Pass-in-Stack-Aufrufkonventionen zu laden, ist die Funktion prolog: 'push bp'' mov bp, sp' ... weiter mit proc body ... 'mov ax, [bp +4]; arg1' 'add ax, [bp + 6]; arg2'' Unteraxt, 2 * '0'' 'mov [suma], ax' und endend mit Epilog, der den Stack wiederherstellt' mov sp, bp; kann weggelassen werden, wenn sp richtig ist "pop bp" 'ret' .. oder um deine" args "zu simulieren, die durch proc" ret 4 "entfernt wurden, um die zwei Argumente (4B) nach" ret "zu entfernen. – Ped7g

Antwort

0

push bx Bedarf hinzugefügt werden:

code segment 

    sumUp proc 

     pop bx 
     pop ax 
     sub ax, 30h 

     mov suma, ax 
     pop ax 
     sub ax, 30h 
     add suma, ax 

     push bx ; needs to be added here 
    ret 
    sumUP endp 
+0

Sie ändern die 'sp' des Aufrufers, indem Sie das tun. Bei einigen Aufrufkonventionen muss der Angerufene die Argumente vom Stapel entfernen, aber normalerweise wird dies mit "ret 4" gemacht (um das Äquivalent von "add sp, 4" nach dem Aufrufen der Rückkehradresse zu machen). Wenn Ihr Anrufer nicht erwartet, dass Ihre Funktion das tut, ist es schlecht. Ihre Funktion ist sehr ineffizient, BTW. Sie sollten in zwei verschiedene Register statt in 'suma' springen. Oder erstellen Sie einen Stapelrahmen, so dass Sie wahlfrei auf den Stapelspeicher zugreifen können. –

1

Sie verwirren die Rücksprungadresse auf dem Stack nach oben, so dass es nicht dort, wo n ret will es pop (in IP).

Anstatt für den Zugriff auf Daten auf dem Stapel zu springen, richten Sie bp als Rahmenzeiger ein, damit Sie als Basisregister auf den Stapelspeicher zugreifen können.

Sie müssen die bp Ihres Anrufers speichern/wiederherstellen; normalerweise mit push/pop, aber in diesem Fall können wir es in cx (die Sie nicht speichern/wiederherstellen müssen), da die Funktion einfach ist und nicht mehrere temporäre Register benötigt.

; multi-segment executable file template. 

data segment 
    message1 db "Enter 2 number..$" 
ends 

stack segment 
    dw 128 dup(0) 
ends 

code segment 

    ; inputs: first arg in AX, 2nd arg on the stack 
    ; clobbers: CX 
    ; returns in: AX 
    sumUp proc 

     mov cx, bp  ; save caller's BP 
     mov bp, sp 
     mov ax, ss:[bp+2] ; get the value of pushed parameter without messing with top of the stack   
     mov bp, cx  ; restore it. 

     ret 

    sumUP endp 

start: 
; set segment registers: 
    mov ax, data 
    mov ds, ax 
    mov es, ax 

; add your code here 

    lea dx,message1 
    mov ah,09h 
    int 21h 

    mov ah,1h 
    int 21h   

    mov ah, 0 
    sub al, 30h 

    push ax 

    mov ah,1h 
    int 21h 

    mov ah, 0 
    sub al, 30h 
    ; no need to push second operand because its already in ax 
    call sumUp        

    ; result in ax 

    mov ah, 04ch 
    int 21h 

ends 

end start ; set entry point and stop the assembler. 
+0

@Peter Cordes Wie ist es mit diesem Code ist es optimiert? : D – Ahtisham

+0

Sieht ziemlich schrecklich aus. Erstellen Sie einen Stack-Frame auf die übliche Weise, so dass Sie ret verwenden können (und vergessen Sie nicht, den "bp" des Aufrufers zu speichern). Es macht keinen Sinn, 'call' zu verwenden, wenn Sie' jmp resume' verwenden, und nicht übereinstimmender call/ret den Repeat-Stack für die Rücksprungadressen bricht, so dass Sie später Verzweigungen in einigen späteren 'ret'-Anweisungen erhalten . –

+0

Die Maschinencodierung von '[bp]' benötigt ein extra Byte für eine disp8 = 0, dh '[bp + 0]' (wenn 16-bit gleich 32-bit ist), weil es keine Kodierung für ' [bp] 'ohne Verschiebung. Dies ist sinnvoll, weil '[bp]' auf den gespeicherten Wert des 'bp' des Aufrufers zeigt, auf den Sie nicht zugreifen müssen, wenn Sie einen Stack-Frame auf normale Weise erstellen. Sie können '[bp + 4]' verwenden, um auf das erste Argument zuzugreifen. (oder 2. wenn du den ersten in "axe" passierst). Also sollten Sie 'push bp' /' mov bp, sp'/'add ax, [bp + 4]' (SS: ist implizit für BP)/'pop bp' /' ret'. ('leave' würde auch funktionieren, aber du hast' sp' nicht geändert.) –

Verwandte Themen