我正在使用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
答案 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
指令遗忘一次DOS
或CALL 0
序列以终止RST 0
中的程序