3

I have the following code, which takes a number in hexadecimal format and prints out its decimal format.

This program runs kinda fine in Turbo Debugger, but when I run it in DOS, I see some extra symbols in output after my number output:

.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

Output:

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$♦♦

As you can see 65535 prints ok, but then garbage appears. When I run the program in Turbo Debugger, it hangs after writing out 65535.

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
vladfau
  • 1,003
  • 11
  • 22

2 Answers2

6

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 ndirective (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.)
Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • I'm glad to see your answer. I upvoted because you deserve it. I don't accept credit for someone else's work (which you kind of hinted at me doing with comments on my answer). – owacoder Oct 09 '15 at 00:39
  • @owacoder I waited a while and then figured you were waiting for me ;-). Actually I wasn't hinting at anything with regards to comments on your answer. I actually don't care about reputation points like others (and did appreciate you mentioning me in your answer). you'll often find I leave responses to trivial questions as a comment rather than an answer, and have no issue if answers appear that may be similar to my comments. – Michael Petch Oct 09 '15 at 00:42
  • Thanks, I accept this answer as program works fine now. Note about `int 20h` is clear to me. However, I didn't understand the `cx` thing. In debugger I see that CX is set to zeroes on the program startup. Why should I explicitly set it? – vladfau Oct 09 '15 at 06:29
  • 1
    @ka2m : _CX_ is considered undefined (so is _BP_,_BX_, _DX_, _SI_, _DI_) upon entry to your _EXE_ program. Because it is undefined it may or may not contain 0. Sometimes when you run a debugger against an executable the value of _CX_ might be zero and if run outside the debugger it may not be zero. It really could be anything. To see information about the state of registers when an EXE loads see the bottom of this [article](http://www.tavi.co.uk/phobos/exeformat.html) in section _Register contents at program entry_ – Michael Petch Oct 09 '15 at 06:36
3

It looks like the loop print continues past the end of the number because you do not initialize CX to zero beforehand. (Thanks to @MichaelPetch, I found this at the same time his comment appeared) I would change your save routine to look something like this:

save proc
    xor cx,cx
    itm:
owacoder
  • 4,815
  • 20
  • 47
  • Although this fixes part of the problem, the OP did mention that their program hangs as well, and that is because he is using `int 20h` inside an _EXE_. Although you can get it to work in an _EXE_ by changing the _CS_ it is generally preferred to use `int 21h` with _ah=04ch_ and _al_ the return code. `int 20h` is more common for COM programs (although there a simple `retn` works as well) – Michael Petch Oct 08 '15 at 22:35
  • @MichaelPetch - Why not post an answer? – owacoder Oct 08 '15 at 22:37
  • Because you already have an answer. Pointless for me to add a new one and duplicate it and adding a new section.I don't care about reputation points so who gets them doesn't matter. If a single answer can be used to answer both problems, I'd rather see that than 2 separate answers. – Michael Petch Oct 08 '15 at 22:38
  • If you have further insight, posting another answer wouldn't be "pointless." – owacoder Oct 08 '15 at 22:38