TASM 程序输出垃圾并可能在退出时挂起

TASM program outputs garbage and may hang upon exit

我有以下代码,它接受一个十六进制格式的数字并打印出它的十进制格式。

这个程序 运行 在 Turbo Debugger 中还不错,但是当我在 DOS 中 运行 它时,我在数字输出后看到一些额外的符号输出:

.model small
.stack 100h
.486
.code

save proc
    itm:
        xor dx,dx
        mov bx,10
        div bx
        add dl,30h
        inc cx
        pop bx
        push dx
        push bx
        cmp ax,0
        jne itm
   ret
save endp

start:
    mov ax, 0FFFFh
    call save
    mov ah, 02
    print:
        pop dx
        int 21h
        loop print
       int 20h
end start

输出:

C:\TASM>lab31 65535 ò Φ■╤  9°☻░╧♠UWSîÄPA÷0ó♥┴∞└εê$♦ó♥α♦▲ê$ó♦Σê←ë♦ó♥☻╨sÄ÷♣t╣ ╞ ÷┤ⁿ8sê¬ê²≤&mî│░ⁿ┘╗♥÷ t<sÿ☻╪╟♣I☼>♥b!├─4&Gê&_ëΩî∞[┴éΦ z│Φ ☺\│Φ ♀fδ[♥3¡ïA1èG┴├═≥uè ç♦└┌é─Ω╕↕ëX╪♥♦♫↕Y^▼Z╖ ←tÇ5▲♦▼δá♦├☻├ █ ☻┬! C└(A∞1▬:↕ÿ├ƒ♥╞[%█☼C└≥░Φ 1357                46$♦♦

如您所见,65535 打印正常,但随后出现垃圾。当我 运行 Turbo Debugger 中的程序时,它在写出 65535 后挂起。

看起来循环 print 继续过了数字的末尾,因为您没有事先将 CX 初始化为零。 (感谢@MichaelPetch,我在他的评论出现的同时发现了这一点)我会改变你的save例程看起来像这样:

save proc
    xor cx,cx
    itm:

您的代码有几个问题。您使用 CX 作为您的字符计数器,但是在这段代码中您在没有初始化的情况下递增:

save proc
    itm:
        xor dx,dx
        mov bx,10
        div bx
        add dl,30h
        inc cx                 ; increment CX, without initialization
        pop bx
        push dx
        push bx
        cmp ax,0
        jne itm
   ret
save endp

要解决此问题,您可以通过在 save 过程的主循环外将其初始化,将 CX 设置为零:

save proc
        xor cx,cx              ; Explicitly clear CX counter.            
    itm:
        xor dx,dx

要在 EXE 加载时查看有关寄存器状态的信息,请参阅本文底部的 register contents at program entry:

部分
Register  Contents
AX        If loading under DOS: AL contains the drive number for the first FCB 
          in the PSP, and AH contains the drive number for the second FCB.
BX        Undefined.
CX        Undefined.
DX        Undefined.
BP        Undefined.
SI        Undefined.
DI        Undefined.
IP        Initial value copied from .EXE file header.
SP        Initial value copied from .EXE file header.
CS        Initial value (relocated) from .EXE file header.
DS        If loading under DOS: segment for start of PSP.
ES        If loading under DOS: segment for start of PSP.
SS        Initial value (relocated) from .EXE file header.

寄存器 CX 被认为是未定义的(BP,BX,DX,SI,DI) 进入你的 EXE 程序。 AX 可能不为零,因为它用于将信息传递给您的 EXE。因为 CX 未定义,它可能包含也可能不包含 0。

有时,当您 运行 针对可执行文件的调试器时, CX 的值可能与没有调试器的 运行ning 不同。对于 Turbo Debugger,CX 在输入时似乎为零。如果你 运行 你的程序在调试器之外,它可能不是零,并且会导致像你遇到的问题。我建议在使用它们之前初始化您的通用寄存器。

至于程序末尾的挂起是因为您正在使用 int 20h。您的代码表明您正在生成 .EXE 文件(而不是 .COM)。退出 .EXE 程序的典型方法是使用 int 21h 其中 AH=04chAL 是您的退出代码。如果将 int 20h 替换为以下代码,它将以 return 值 0 退出:

   mov ax, 4c00h
   int 21h

使用 TASM 您还可以使用 .exit n 指令(n = 退出 return 值)作为替代。这应该会生成适当的汇编代码以退回 DOS。

int 20h.COM程序中经常使用(retn更常见)。 int 20h 依赖于 CS:0 作为 PSP block. This will be true by default in a .COM program, but in an .EXE program this isn't the case. More information on this can be found here and here:

的地址

Int 21h Function 4Ch

   Notes:         It is best to use INT 21h Function 4Ch to exit from
                  '.exe' programs since Function 4Ch doesn't require
                  that CS point to the PSP.

Int 20h

   Notes:         This function is an historical remnant offering no
                  advantages over Function 4Ch. It's better to use
                  function 4Ch, which returns an error code that other
                  programs can access (via Function 4Dh or the
                  ERRORLEVEL statement in batch files); also, CS need
                  not be set first when using Function 4Ch. (INT 20h
                  is equivalent to Function 0.)