我正在尝试编写一个子程序,该子程序将计算16位数中设置的buts数,然后将该数字(位设置)发送回AX中的主程序。主屏幕应显示1的数字,并确定该数字是偶数还是奇数。
我试图通过左移和递增来计算1。问题似乎是当我回到'main'时,原始输入数字仍然是AX,而不是我在“奇偶校验”中得到的计数。我不知道为什么不改变。
;===================================================================
; MAIN.ASM
;===================================================================
EXTERN GETDEC$:FAR
EXTERN NEWLINE:FAR
EXTERN PUTSTRNG:FAR
EXTERN PUTDEC$:FAR
EXTERN PUTBIN:FAR
EXTERN PARITY:FAR
;===================================================================
.MODEL LARGE
.STACK 512
;===================================================================
; D A T A S E G M E N T D E F I N I T I O N
.DATA
NUMBER DW ?
PROMPT DB 'Enter a number: '
BINDISPLAY DB 'Number in binary: '
ONESDISPLAY DB 'Number of 1s: '
ODDDISPLAY DB 'The number of 1s is odd. '
EVENDISPLAY DB 'The number of 1s is even. '
;===================================================================
; C O D E S E G M E N T D E F I N I T I O N
.CODE
ASSUME DS:DGROUP
;===================================================================
MAIN PROC
MOV AX,DGROUP ;SET DS-REGISTER TO POINT TO
MOV DS,AX ;DATA SEGMENT
MOV ES,AX ;AND ES ALSO
CALL NEWLINE
MOV DI, OFFSET PROMPT
MOV CX, SIZEOF PROMPT
CALL PUTSTRNG
CALL GETDEC$
CALL NEWLINE
MOV DI, OFFSET BINDISPLAY
MOV CX, SIZEOF BINDISPLAY
CALL PUTSTRNG
CALL PUTBIN
PUSH AX
CALL PARITY
CALL NEWLINE
CALL NEWLINE
MOV DI, OFFSET ONESDISPLAY
MOV CX, SIZEOF ONESDISPLAY
CALL PUTSTRNG
POP AX
CALL PUTDEC$
CALL NEWLINE
SUB DX, DX
MOV BX, 2
DIV BX
CMP DX, 0
JNE ODDS
MOV DI, OFFSET EVENDISPLAY
MOV CX, SIZEOF EVENDISPLAY
CALL NEWLINE
CALL PUTSTRNG
JMP EXIT_PROGRAM
ODDS:
MOV DI, OFFSET ODDDISPLAY
MOV CX, SIZEOF ODDDISPLAY
CALL NEWLINE
CALL PUTSTRNG
EXIT_PROGRAM:
.EXIT
MOV AX, 4C00H
INT 21H
MAIN ENDP
END MAIN
;;===================================================================
; Veronica Kaufman
; CISP 310
; PARITY.ASM
;===================================================================
.MODEL LARGE
;===================================================================
; D A T A S E G M E N T D E F I N I T I O N
.DATA
ONES_COUNT DW 0
;===================================================================
; C O D E S E G M E N T D E F I N I T I O N
.CODE
ASSUME DS:DGROUP
;===================================================================
PARITY PROC FAR PUBLIC USES CX DX DS
POP AX
NUM_LOOP:
CMP AX, 0
JE END_PROGRAM
SHL AX, 1
JC INCREMENT
JMP NUM_LOOP
INCREMENT:
INC ONES_COUNT
JMP NUM_LOOP
END_PROGRAM:
MOV AX, ONES_COUNT
PUSH AX
RET
PARITY ENDP
END PARITY
答案 0 :(得分:3)
我认为这样做的意图是PARITY
将在堆栈上接受一个参数,然后修改该参数,将其保留在堆栈中的相同位置:
; (This does not work, see below)
...
PUSH AX ; input value
CALL PARITY ; want this to change it in-place...
...
POP AX ; ...so that this pops off the output value
CALL PUTDEC$
...
PARITY PROC FAR PUBLIC USES CX DX DS
POP AX ; get argument from stack
...
PUSH AX ; put result back on stack
RET
这不起作用,原因有两个:
CALL
将返回地址压入堆栈。PROC
... USES
生成的序言代码会将更多内容推送到堆栈中。当你在POP AX
内PARITY
时,你实际上会弹出一些完全不同的东西(然后将其他东西放回原位) - 可能是序言中保存的其他寄存器之一。 / p>
做得对的选项:
如果你理解这里使用的调用约定,你应该能够找到被推入堆栈的AX
的位置,很可能是在{{1}的某个小偏移处。注册(我不太熟悉MASM,以确切知道BP
生成的序言代码在这种情况下的作用),并直接加载/存储它。
或者,使PROC
获取其输入并直接在PARITY
寄存器中返回其输出。在这种情况下,您需要在AX
之前移除PUSH AX
(输入已在CALL PARITY
中),然后在 {{1}之后直接将放入其中而不是(保存返回的结果,稍后将弹出 - 我假设AX
需要保存,因为它可能被其他调用损坏);并从CALL
中删除AX
和POP AX
。