3

我有以下代码,它采用十六进制格式的数字并打印出其十进制格式。

这个程序在 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ê¬ê²≤&amp;mî│░ⁿ┘╗♥÷ t<sÿ☻╪╟♣I☼&gt;♥b!├─4&Gê&_ëΩî∞[┴éΦ z│Φ ☺\│Φ ♀fδ[♥3¡ïA1èG┴├═≥uè ç♦└┌é─Ω╕↕ëX╪♥♦♫↕Y^▼Z╖ ←tÇ5▲♦▼δá♦├☻├ █ ☻┬! C└(A∞1▬:↕ÿ├ƒ♥╞[%█☼C└≥░Φ 1357                46$♦♦

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

4

2 回答 2

6

您的代码有几个问题。您将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

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

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

要查看有关加载EXE时寄存器状态的信息,请参阅本文底部程序入口处的寄存器内容部分:

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.

在进入您的EXE程序时,寄存器CX被视为未定义(BPBXDXSIDI也是如此)。AX可能不为零,因为它用于将信息传递给您的EXE。因为CX未定义,它可能包含也可能不包含 0。

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

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

   mov ax, 4c00h
   int 21h

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

int 20h在.COM程序中经常使用(retn更常见) 。依赖于CS:0PSP块的地址。这在.COM程序中默认为真,但在.EXE程序中并非如此。更多信息可以在这里这里找到:int 20h

诠释 21h 功能 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.

国际 20 小时

   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.)
于 2015-10-08T23:57:22.953 回答
3

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

save proc
    xor cx,cx
    itm:
于 2015-10-08T21:15:40.207 回答