Assembly 程序集中另一个程序内的程序调用
我正在使用tasm,试图在另一个过程中调用一个过程。但是,当程序从第二个过程返回时,IP设置为0000,而不是返回到调用它的点。有人能解释一下为什么会这样吗? 以下是代码的一部分: 主要程序:Assembly 程序集中另一个程序内的程序调用,assembly,x86,procedure,Assembly,X86,Procedure,我正在使用tasm,试图在另一个过程中调用一个过程。但是,当程序从第二个过程返回时,IP设置为0000,而不是返回到调用它的点。有人能解释一下为什么会这样吗? 以下是代码的一部分: 主要程序: MAIN PROC FAR ; main proc MUST be FAR ASSUME CS:COD1,DS:DATA1,SS:STCK PUSH DS ;save DS on stack for OS return XOR AX,AX ; PUSH A
MAIN PROC FAR ; main proc MUST be FAR
ASSUME CS:COD1,DS:DATA1,SS:STCK
PUSH DS ;save DS on stack for OS return
XOR AX,AX ;
PUSH AX ;put 0 on stack for OS return
MOV AX,DATA1
MOV DS,AX ;load data Segement register
CALL PLAY
RET ; return to OS
MAIN ENDP
PLAY PROC NEAR
RPT:
MOV AH,00H ;read ch from stdin
INT 16H
CMP AH,48H
JE UP
CMP AH,4BH
JE LEFT
CMP AH,50H
JE DOWN
CMP AH,4DH
JE RIGHT
CMP AH,01H
JE ESCAPE
UP:
CALL MOVEUP
JMP RPT
DOWN:
CALL MOVEDOWN
JMP RPT
LEFT:
CALL MOVELEFT
JMP RPT
RIGHT:
CALL MOVERIGHT
JMP RPT
ESCAPE:
RET
PLAY ENDP
MOVEUP PROC NEAR ;tries to update position of player if down key pressed
PUSH DX
PUSH AX
PUSH SI ;save all general registers to stack
MOV AL,X ;compute index for current position
MOV DL,15
MUL DL
MOV DL,Y
MOV DH,0
ADD AX,DX
MOV SI,AX
PUSH SI ;save it for later
MOV DL, X ;current x coord
MOV DH, Y ;current y coord
SUB DL, 1
MOV NEWX,DL ;new x coord
MOV NEWY,DH ;new y coord
MOV AL,NEWX ;store new x coord in AL
MOV AH,0 ;make ah 0 to "extend" new x on 2B
CMP AL,0 ;check if new x in bounds (>=0)
JL NOT_OK_UP
MOV DL,15 ;compute index of position: index=15*x+y
MUL DL
MOV DL,NEWY
MOV DH,0
ADD AX,DX
MOV SI,AX
MOV DL,MAZE[SI] ;fetch element on position newx,newy
CMP DL,1 ;if wall, go to end of procedure(nop)
JE NOT_OK_UP
MOV DL,NEWX
MOV DH,NEWY
MOV X,DL ;update x
MOV Y,DH ;update y
MOV MAZE[SI],2 ;update position in maze
POP SI
MOV MAZE[SI],0 ;clean up old position
NOT_OK_UP:
POP SI
POP AX
POP DX
RET
MOVEUP ENDP
第一个调用的过程:
MAIN PROC FAR ; main proc MUST be FAR
ASSUME CS:COD1,DS:DATA1,SS:STCK
PUSH DS ;save DS on stack for OS return
XOR AX,AX ;
PUSH AX ;put 0 on stack for OS return
MOV AX,DATA1
MOV DS,AX ;load data Segement register
CALL PLAY
RET ; return to OS
MAIN ENDP
PLAY PROC NEAR
RPT:
MOV AH,00H ;read ch from stdin
INT 16H
CMP AH,48H
JE UP
CMP AH,4BH
JE LEFT
CMP AH,50H
JE DOWN
CMP AH,4DH
JE RIGHT
CMP AH,01H
JE ESCAPE
UP:
CALL MOVEUP
JMP RPT
DOWN:
CALL MOVEDOWN
JMP RPT
LEFT:
CALL MOVELEFT
JMP RPT
RIGHT:
CALL MOVERIGHT
JMP RPT
ESCAPE:
RET
PLAY ENDP
MOVEUP PROC NEAR ;tries to update position of player if down key pressed
PUSH DX
PUSH AX
PUSH SI ;save all general registers to stack
MOV AL,X ;compute index for current position
MOV DL,15
MUL DL
MOV DL,Y
MOV DH,0
ADD AX,DX
MOV SI,AX
PUSH SI ;save it for later
MOV DL, X ;current x coord
MOV DH, Y ;current y coord
SUB DL, 1
MOV NEWX,DL ;new x coord
MOV NEWY,DH ;new y coord
MOV AL,NEWX ;store new x coord in AL
MOV AH,0 ;make ah 0 to "extend" new x on 2B
CMP AL,0 ;check if new x in bounds (>=0)
JL NOT_OK_UP
MOV DL,15 ;compute index of position: index=15*x+y
MUL DL
MOV DL,NEWY
MOV DH,0
ADD AX,DX
MOV SI,AX
MOV DL,MAZE[SI] ;fetch element on position newx,newy
CMP DL,1 ;if wall, go to end of procedure(nop)
JE NOT_OK_UP
MOV DL,NEWX
MOV DH,NEWY
MOV X,DL ;update x
MOV Y,DH ;update y
MOV MAZE[SI],2 ;update position in maze
POP SI
MOV MAZE[SI],0 ;clean up old position
NOT_OK_UP:
POP SI
POP AX
POP DX
RET
MOVEUP ENDP
第二个调用过程的模型:
MAIN PROC FAR ; main proc MUST be FAR
ASSUME CS:COD1,DS:DATA1,SS:STCK
PUSH DS ;save DS on stack for OS return
XOR AX,AX ;
PUSH AX ;put 0 on stack for OS return
MOV AX,DATA1
MOV DS,AX ;load data Segement register
CALL PLAY
RET ; return to OS
MAIN ENDP
PLAY PROC NEAR
RPT:
MOV AH,00H ;read ch from stdin
INT 16H
CMP AH,48H
JE UP
CMP AH,4BH
JE LEFT
CMP AH,50H
JE DOWN
CMP AH,4DH
JE RIGHT
CMP AH,01H
JE ESCAPE
UP:
CALL MOVEUP
JMP RPT
DOWN:
CALL MOVEDOWN
JMP RPT
LEFT:
CALL MOVELEFT
JMP RPT
RIGHT:
CALL MOVERIGHT
JMP RPT
ESCAPE:
RET
PLAY ENDP
MOVEUP PROC NEAR ;tries to update position of player if down key pressed
PUSH DX
PUSH AX
PUSH SI ;save all general registers to stack
MOV AL,X ;compute index for current position
MOV DL,15
MUL DL
MOV DL,Y
MOV DH,0
ADD AX,DX
MOV SI,AX
PUSH SI ;save it for later
MOV DL, X ;current x coord
MOV DH, Y ;current y coord
SUB DL, 1
MOV NEWX,DL ;new x coord
MOV NEWY,DH ;new y coord
MOV AL,NEWX ;store new x coord in AL
MOV AH,0 ;make ah 0 to "extend" new x on 2B
CMP AL,0 ;check if new x in bounds (>=0)
JL NOT_OK_UP
MOV DL,15 ;compute index of position: index=15*x+y
MUL DL
MOV DL,NEWY
MOV DH,0
ADD AX,DX
MOV SI,AX
MOV DL,MAZE[SI] ;fetch element on position newx,newy
CMP DL,1 ;if wall, go to end of procedure(nop)
JE NOT_OK_UP
MOV DL,NEWX
MOV DH,NEWY
MOV X,DL ;update x
MOV Y,DH ;update y
MOV MAZE[SI],2 ;update position in maze
POP SI
MOV MAZE[SI],0 ;clean up old position
NOT_OK_UP:
POP SI
POP AX
POP DX
RET
MOVEUP ENDP
如果执行“call”指令,则返回地址将被推送到堆栈上,如果执行“ret”指令,则地址将从堆栈中弹出。但是,如果我们在子例程内部使用“push”指令,而在末尾没有pop指令,那么堆栈顶部就不包含返回地址。因此,如果我们在从堆栈中弹出其他值之前执行“ret”指令,那么这些值将被用作返回地址。另一个问题是在一个子例程中调用一个子例程,而不控制我们使用了多少实例。为了增加Dirk的注释,标记为
的PUSH SI
将其保存到以后的,当你跳转到NOT_OK\u UP
时,它不会再次正确弹出。我修改了代码,添加了正确的弹出窗口,现在就可以工作了。非常感谢您的解释和指出错误!