程序返回不正确

时间:2013-12-31 17:28:58

标签: assembly call procedure

我正在使用TASM进行程序集8086,我有两个文件。我从一个文件中调用read过程,并希望在另一个文件中使用它3次。第一次使用程序崩溃后。

read.asm文件:

PUBLIC READ
DATA SEGMENT PARA PUBLIC 'DATA'
BUFFER DB 200 DUP(?)
FLAG DB 0
DATA ENDS

CODE SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CODE, DS:DATA
;PUBLIC READ

; read procedure reads a string character by character from the keyboard 
READ PROC FAR
PUSH DS
    XOR AX,AX
    PUSH AX
    MOV AX,DATA
    MOV DS,AX
    XOR DI,DI

; readloop is the loop for reading the string character by character
READLOOP:
    MOV AH,01H
    INT 21H; al will get the character
    MOV BUFFER[DI],AL; the character is stored
    INC DI
    CMP AL,0DH
    JNZ READLOOP; the reading continues until the ENTER key is pressed

; we display the string
    MOV AL,0
    MOV BUFFER[DI],24H
    LEA DX,BUFFER
    MOV AH,09H
    INT 21H

; converting the string to a real number
    XOR SI,SI
    XOR DX,DX
    MOV DL,BUFFER[SI]
    XOR AX,AX
    XOR CX,CX

; converter loop converts the string to a real number memorizing where the decimal point was
CONVERTER:
    CMP DL,2EH; searching for the decimal point
    JZ FLOATINGPOINT
    CMP FLAG,1
    JNZ NEXT2
    INC CX; position of the decimal point stored

NEXT2:
    SUB DL,30H; deducing the character which digit is
    PUSH DX; storing the value of dx on the stack
    MOV BX,10
    MUL BX
    POP DX
    ADD AX,DX; retrieving the value as an integer in AX
    JMP NEXT

FLOATINGPOINT:
    MOV FLAG,1

NEXT:
    INC SI
    MOV DL,BUFFER[SI]
    CMP DL,0DH; doing the conversion until the ENTER key is pressed
    JNZ CONVERTER
    RET
READ ENDP

SAMPLE PROC FAR
    RET
SAMPLE ENDP
CODE ENDS
    END SAMPLE

main.asm文件:

GLOBAL READ:FAR
DATA SEGMENT PARA PUBLIC 'DATA'
SIDEONE DW ?
SIDETWO DW ?
SIDETHREE DW ?
HALFPERIMETER DB ?
DECIMALPOINTONE DB ?
DECIMALPOINTTWO DB ?
DECIMALPOINTTHREE DB ?
MESSAGE1 DB 10,13,10,13,"Please input the length of the first side:$"
MESSAGE2 DB 10,13,"Please input the length of the second side:$"
MESSAGE3 DB 10,13,"Please input the length of the third side:$"
WELCOMEMESSAGE DB "Welcome to my triangle area calculator!$"
CONTINUEMESSAGE DB 10,13,10,13,"Do you want another try? y-yes n-no:$"
RESULTMESSAGE DB 10,13,10,13,"The area of the triangle is:$"
RESULT DB ?
DATA ENDS

CODE SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CODE, DS:DATA
MAIN PROC FAR
    PUSH DS
    XOR AX,AX
    PUSH AX
    MOV AX,DATA
    MOV DS,AX
    MOV DX,OFFSET WELCOMEMESSAGE
    MOV AH,09H
    INT 21H
    XOR DX,DX
    XOR AX,AX

START:
    LEA DX,MESSAGE1
    MOV AH,09H
    INT 21H
    XOR DX,DX
    CALL READ
    MOV SIDEONE,AX
    MOV DECIMALPOINTONE,CL
    XOR DX,DX
    XOR AX,AX
    LEA DX,MESSAGE2
    MOV AH,09H
    INT 21H
    XOR DX,DX
    CALL READ
    MOV SIDETWO,AX
    MOV DECIMALPOINTTWO,CL
    XOR DX,DX
    XOR AX,AX
    LEA DX,MESSAGE3
    MOV AH,09H
    INT 21H
    XOR DX,DX
    CALL READ
    MOV SIDETHREE,AX
    MOV DECIMALPOINTTHREE,CL
    XOR DX,DX
    XOR AX,AX
    LEA DX,RESULTMESSAGE
    MOV AH,09H
    INT 21H
    XOR DX,DX
    ;MOV DX,RESULT
    ;MOV AH,09H
    ;INT 21H
    ;XOR DX,DX
    XOR AX,AX
    MOV DX,OFFSET CONTINUEMESSAGE
    MOV AH,09H
    INT 21H
    MOV AH,01H
    INT 21H
    CMP AL,79H
    JZ START
    CMP AL,6EH
    JZ FINISHPROGRAM

FINISHPROGRAM:
    MOV AH,4CH
    INT 21H
    RET
MAIN ENDP
CODE ENDS
END MAIN

1 个答案:

答案 0 :(得分:2)

这是你砸碎了堆栈。就在READ程序的开头:

PUSH DS
XOR AX,AX
PUSH AX

在EXE程序开始时需要这个序列,以便用RET FAR指令(一种终止EXE文件btw的旧方法)完成它,但在任何程序中都不需要它你的程序调用。删除它。

此外,只要程序中的任何一点都未更新DS,您只需要在程序开头一次MOV AX,DATA / MOV DS,AX序列,而不是每个程序。

如果以这种方式终止程序,则可以有效地避免上述序列:

MOV AX,4C00h
INT 21h

终止DOS进程的正确方法是什么。旧的方法是使用INT 20h,但INT 20h需要CS指向程序的PSP,因此PUSH DS / XOR AX,AX / PUSH AX序列:{{1}指令将加载RET FAR,其值为CS:IP,继续执行DS:0000h开头的执行PSP加载INT 20h指令遗忘一次DOSCALL 0序列以终止RST 0中的程序