There are a couple of problems with your code. You use CX
as your character counter, however in this code you increment without initialization:
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
To fix this, you can set CX to zero by initializing it outside the main loop in your save
procedure:
save proc
xor cx,cx ; Explicitly clear CX counter.
itm:
xor dx,dx
To see information about the state of registers when an EXE loads see the bottom of this article in section 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.
Register CX is considered undefined (so is BP,BX,DX,SI,DI) upon entry to your EXE program. AX likely will be non-zero since it is used to pass information to your EXE. Because CX is undefined it may or may not contain 0.
Sometimes when you run a debugger against an executable the value of CX might be different than running without the debugger. In the case of Turbo Debugger, CX appears to be zero upon entry. If you run your program outside the debugger it may not be zero, and would cause problems like you encountered. I recommend initializing your general purpose registers before using them.
As for the hang at the end of your program that is because you are using int 20h
. Your code suggests you are generating .EXE file (not .COM). The typical way to exit an .EXE program is to use int 21h
where AH=04ch and AL is your exit code. If you replace int 20h
with the following code it will exit with return value of 0:
mov ax, 4c00h
int 21h
With TASM you can also use the .exit n
directive (n = exit return value) as an alternative. This should generate the appropriate assembler code to exit back to DOS.
int 20h
is often used (retn
more common) in .COM programs. int 20h
relies on CS:0 being the address of the 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.)