我正在使用 TASM(在 DosBOX 模拟器中)。
我是初学者,还不太了解。
下面是我的完整代码。问题是它不仅打印出预期的输出(25 + 10 = 35 和 25 - 10 = 15),而且还打印出一些垃圾并且程序冻结:
SSEG segment stack
db 256 dup(0)
SSEG ends
DSEG segment
num1 dw 25
num2 dw 10
new_line db 0dh,0ah,'$'
msg_add db '25 + 10 = ','$'
msg_sub db '25 - 10 = ','$'
DSEG ends
CSEG segment
assume cs:CSEG,ds:DSEG,ss:SSEG
begin:
mov ax, DSEG
mov ds, ax
; ADD
mov ah, 09h
mov dx, offset msg_add
int 21h
mov ax, num1
mov bx, num2
add ax, bx
mov ax, ax
call print_number
; SUB
mov ah, 09h
mov dx, offset msg_sub
int 21h
mov ax, num1
mov bx, num2
sub ax, bx
mov ax, ax
call print_number
print_number proc
mov si,10
mov cx,0
a:
mov dx,0
div si
add dx,'0'
push dx
inc cx
cmp ax,0
jnz a
aa:
pop dx
mov ah,02h
int 21h
loop aa
mov ah, 09h
mov dx, offset new_line
int 21h
ret
print_number endp
mov ah,4ch
int 21h
CSEG ends
end begin
我尝试了将参数传递给函数的不同方法。为了最小化代码,我只列出了 ADD(与 SUB 的逻辑相同)
mov ah, 09h
mov dx, offset msg_add
int 21h
mov ax, num1
mov bx, num2
add ax, bx
push ax
call print_number
我尝试了在 print_number 中弹出和推送 ax 寄存器
爆裂声:
print_number proc
pop ax
mov si,10
mov cx,0
a:
mov dx,0
div si
add dx,'0'
push dx
inc cx
cmp ax,0
jnz a
aa:
pop dx
mov ah,02h
int 21h
loop aa
mov ah, 09h
mov dx, offset new_line
int 21h
ret
print_number endp
推:
print_number proc
push ax
mov si,10
mov cx,0
a:
mov dx,0
div si
add dx,'0'
push dx
inc cx
cmp ax,0
jnz a
aa:
pop dx
mov ah,02h
int 21h
loop aa
mov ah, 09h
mov dx, offset new_line
int 21h
ret
print_number endp
就像问题的第一个代码一样
; ADD
mov ah, 09h
mov dx, offset msg_add
int 21h
mov ax, num1
mov bx, num2
add ax, bx
mov ax, ax
call print_number
print_number proc
mov si,10
mov cx,0
a:
mov dx,0
div si
add dx,'0'
push dx
inc cx
cmp ax,0
jnz a
aa:
pop dx
mov ah,02h
int 21h
loop aa
mov ah, 09h
mov dx, offset new_line
int 21h
ret
print_number endp
但是每个代码都不能正常工作。
我期望只有以下两行:
25 + 10 = 35
25 - 10 = 15
每种方法都会打印出垃圾,并且程序会冻结。
我该如何解决这个问题?
打印号码的程序不起作用
mov ax, ax call print_number <--- Here program should end print_number proc mov si,10
打印数字的程序工作正常,但在打印行
25 - 10 = 15
后,程序应该立即终止。因为提及 proc
不会对 CPU 造成障碍,而是简单地在以下几行继续执行,首先打印一个“随机”数字,然后真正的问题开始了,因为 ret
指令结束了 print_number 过程在堆栈上没有合理的返回地址。这就是那种可以冻结程序的东西......call print_number
mov ax, 4C00h
int 21h ; DOS.Terminate
; -------------------
; IN (ax)
print_number proc
mov si, 10
push ax ; (35) call print_number ... print_number proc pop ax mov si, 10 ... ret
这是行不通的,因为
pop ax
不会检索数字 (35),而是检索 call
指令放置在堆栈上的返回地址。稍后,ret
指令会将 (35) 解释为要返回的地址,但是,如您所知,它根本不是一个地址。
push ax call print_number ... print_number proc push ax mov si, 10 ... ret
这是行不通的,因为第二个
push ax
将强制ret
指令返回到错误的地址。此外,压入的参数和正确的返回地址都保留在堆栈上,因此将来某个时候堆栈溢出是预料之中的。
mov ax, ax call print_number ... print_number proc mov si, 10
这是正确的,但是
mov ax, ax
指令没有做任何有用的事情。只是浪费了 2 个字节和少量的时间。