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=04ch 和 AL 是您的退出代码。如果将 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.)
我有以下代码,它接受一个十六进制格式的数字并打印出它的十进制格式。
这个程序 运行 在 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=04ch 和 AL 是您的退出代码。如果将 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.)