从汇编代码中打印字符串出错

3

我刚接触汇编语言,正在学习EMU8086。我写了一段代码打印Testing和ASCII码为50的数字2,但只打印了Testing,忽略了后面的内容。这是怎么回事?

.model tiny
.code

org 100h


main proc

    mov ah, 09h
    mov dx, offset msg
    int 21h 
    mov ah, 4ch
    mov dx ,0  
    mov dl, 2
    add dl, 48
    int 21h      

endp

msg db "Testing$"

end main

在阅读了来自@500-内部服务器错误的评论后,我将我的代码更新为:

.model tiny
.code

org 100h


main proc

    mov ah, 09h
    mov dx, offset msg
    int 21h 
    mov dl, 2
    add dl, 48
    int 21h      

endp

msg db "Testing$"

end main

它仍然无法工作,那么出了什么问题?

当 ah = 4ch 时,对 int 21h 的调用要求程序退出 - dl 的值很可能被该请求完全忽略。 - 500 - Internal Server Error
@500-服务器内部错误 我已经删除了这行代码,但仍然无法正常工作。 - Moe
更新问题,展示代码现在的样子。通常情况下,您需要另一个中断(ah=09h或其他中断)才能输出其他内容。Testing$字符串以$终止。 - 500 - Internal Server Error
2个回答

1

DOS中断INT 21h/AH=9h不需要字符值来打印,而是需要指向以$结尾的字符串的内存偏移量来打印。

DOS 1+ - 将字符串写入标准输出

AH = 09h

DS:DX -> '$'-结尾的字符串

返回值:

AL = 24h ('$'终止字符串,尽管官方文档说明没有返回任何值)(至少在DOS 2.1-7.0和NWDOS上)

如果要使用INT 21h/AH=9h打印单个字符,则需要将该值移动到以$符号结尾的缓冲区中。然后将该缓冲区的地址传递给INT 21h/AH=9h。根据您的第二个示例,以下内容应该可以工作:

.model tiny
.code
org 100h

main proc
    mov ah, 09h             ; DOS Interrupt ah=9h print $ terminated string
    mov dx, offset msg      ; Address of msg 
    int 21h                 ; Int 21h/ah=9h Print msg 
    mov outchar, 48+2       ; Move ASCII val for `2` to outchar buffer
    mov dx, offset outchar  ; Address of the $ terminated outchar buffer in DX
    int 21h                 ; AH is still 9h, so this prints $ terminated string

    mov ax, 4c00h           ; Exit program with return value 0
    int 21h    
endp

msg db "Testing$"           ; msg string
outchar db ?, "$"           ; output buffer for single character terminated with $

end main

你可以直接使用ASCII值,而不是像这样写:mov outchar, 48+2

mov outchar, '2'

或者您可以通过一次调用INT 21h/AH=9h来完成,方法是将您想要的字符放入输出缓冲区的中间:

main proc
    mov outchar, '2'    ; Place the ASCII value for '2' in the output buffer
    mov ah, 09h         
    mov dx, offset msg  
    int 21h             ; Print $ terminated string starting at `msg`
    mov ax, 4c00h
    int 21h             ; Exit with error code 0
endp

msg     db "Testing"
outchar db ?, "$"

这个方法有效的原因是,INT 21h/AH=9h会从偏移量msg开始盲目打印直到找到终止符$。我们首先对outchar处的字符进行替换,这样当执行INT 21h/AH=9h时,它将在内存中遇到Testing2$。一旦遇到$,它就会停止打印,输出看起来像这样:

Testing2


您还可以选择使用两个不同的 DOS (INT 21h) 中断。虽然 INT 21h/AH=9h 打印一个以$ 结尾的字符串,INT 21h/AH=2h 显示一个单个字符:

DOS 1+ - 写入标准输出字符

AH = 02h

DL = 要写入的字符

返回: AL = 上次输出的字符(尽管官方文档没有说明会返回任何内容)(至少在 DOS 2.1-7.0 中)

您可以像之前一样编写程序以显示 msg 字符串,但是您也可以使用 INT 21h/AH=2h 来显示单个字符。您的代码可能看起来像这样:

.model tiny
.code
org 100h

main proc
    mov ah, 09h             ; DOS Interrupt ah=9h print $ terminated string
    mov dx, offset msg      ; Address of msg 
    int 21h                 ; Int 21h/ah=9h Print msg 
    mov ah, 02h             ; DOS interrupt ah=2h print single character
    mov dl, '2'             ; DL = ASCII value of character to print
    int 21h                 ; Int 21h/ah=2h print single character in DL 

    mov ax, 4c00h           ; Exit program with return value 0
    int 21h    
endp

msg db "Testing$"           ; msg string

end main

1
你的第二段代码几乎没问题,你只是忘记在ah中加上服务号告诉int 21h要做什么了:
.model tiny
.code

org 100h


main proc

    mov ah, 09h
    mov dx, offset msg
    int 21h 

    mov ah, 2          ;<==== AH=2 : INT 21H WILL DISPLAY CHARACTER IN DL.
    mov dl, 2
    add dl, 48
    int 21h      

endp

msg db "Testing$"

end main

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接