打印号码的程序不起作用

问题描述 投票:0回答:1

我正在使用 TASM(在 DosBOX 模拟器中)。

我是初学者,还不太了解。

下面是我的完整代码。问题是它不仅打印出预期的输出(25 + 10 = 35 和 25 - 10 = 15),而且还打印出一些垃圾并且程序冻结:

enter image description here


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 的逻辑相同)

  1. 按堆栈
    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
  1. 通过寄存器(不确定我是否做对了)

就像问题的第一个代码一样

; 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

每种方法都会打印出垃圾,并且程序会冻结。

我该如何解决这个问题?

assembly x86-16 tasm dosbox
1个回答
0
投票

打印号码的程序不起作用

mov ax, ax
call print_number
                   <--- Here program should end
print_number proc
  mov si,10

打印数字的程序工作正常,但在打印行

25 - 10 = 15
后,程序应该立即终止。因为提及
proc
不会对 CPU 造成障碍,而是简单地在以下几行继续执行,首先打印一个“随机”数字,然后真正的问题开始了,因为
ret
指令结束了 print_number 过程在堆栈上没有合理的返回地址。这就是那种可以冻结程序的东西......
就像Nassau 在评论中写道,解决方案是:

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 个字节和少量的时间。

© www.soinside.com 2019 - 2024. All rights reserved.