0

I want to print an integer with this code but when i assemble with tasm and run program.exe in dosbox, nothing happens and i think it goes into an infinite loop. Do you have an idea?

data segment para public 'data'
data ends

mycode segment para public 'code'
assume cs:mycode, ds:data

main proc far

    push ds
    xor ax, ax
    push ax
    mov ax, data
    mov ds, ax
    
    mov ax, 123
    mov cx, 0
    
    loop_count:
        mov bl, 10
        inc cx
        div bl
        mov dl, al
        mov al, ah
        xor ah, ah
        push ax
        xor ah, ah
        mov ax, dx
        cmp ax, 0
        jne loop_count
    
    
    loop_print:
        pop dx
        add dx, 30h
        mov ah, 02h
        int 21h
        loop loop_print
        
ret

main endp
mycode ends
end main

  • `mov ax, dx` <-- surely that should be `mov al, dl`? Also, you already cleared `ah` before the `push`. No need to do it again directly afterwards. – Michael Apr 27 '22 at 08:47
  • Single-step your code with a debugger and look at registers. Specifically DH, which you never zero even though you copy DX to AX as the dividend for the next iteration of division. `div bl` does `AX / BL`, not just `AL/BL`. IDK if you were mixing it up with `div bx` which would write the remainder to DX? – Peter Cordes Apr 27 '22 at 08:48

1 Answers1

2

You can find a detailed explanation about printing an integer in Displaying numbers with DOS.

mov dl, al    ; Preserve quotient
mov al, ah    ; \
xor ah, ah    ;  Store a 'cleaned' remainder
push ax       ; /
xor ah, ah
mov ax, dx    ; Restore quotient

You want to store the current remainder on the stack, and you want to store it in a 'cleaned' fashion (with its high byte zero). Because both quotient and remainder are in the AX register, you had to first preserve the current quotient in another register like DL, but for the restoration you used the whole DX register with no guarantee that DH would be empty! This produced a runaway loop.

You can solve this in a number of ways, but I think you should not try to 'clean' what you push on the stack. Use the second loop where you need the character in DL anyway.

This is how printing the byte in AL looks like:

  mov  al, 123

  mov  bl, 10
  mov  cx, sp
loop_count:
  xor  ah, ah
  div  bl
  push ax           ; Remainder is in AH, don't care about AL
  test al, al
  jnz  loop_count
    
loop_print:
  pop  ax           ; Remainder is in AH, don't care about AL
  mov  dl, ah
  add  dl, '0'
  mov  ah, 02h
  int  21h
  cmp  sp, cx
  jb   loop_print
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • 1
    Note that a line comment ending in backslash may be a problem for some assemblers, at least for NASM. – ecm Apr 30 '22 at 11:46