Search code examples
assemblymasm

Assembly Language Loop Not working


I am beginner in assembly language.I want to print 1-9 with spaces. I want to print like this

1 2 3 4 5 6 7 8 9

Here is my code I am using masm this code hangs command prompt.

Why this is not working?

DATA_SEG SEGMENT
DATA_SEG ENDS
CODE_SEG SEGMENT 
        ASSUME CS:CODE_SEG , DS:DATA_SEG
MAIN PROC FAR
    MOV AH,02
    MOV AX,'0'
    MOV CX,10
L1:
    MOV DX,AX
    INT 21H
    INC AX
    LOOP L1

    MOV AX,4C00H 
    INT 21H
    MAIN ENDP
CODE_SEG ENDS
END MAIN    

Solution

  • MOV AH,02
    MOV AX,'0'   ; sets ah=0.  this is your bug (there may be others).
    

    The following loop prints all the digits, but doesn't leave spaces. I'll leave that up to you. (edit: oops, this prints digits from 0..9, because that's what your code was doing with the inc after the system call, and starting with '0'. Obviously start with '1' instead.)

        MOV   AH, 2
        mov   dl, '0'
    .l1:
        INT   21H
        INC   dl
        cmp   dl, '9'
        jle .l1
    

    assuming int 21 / ah=2 prints the character in dl. int 21 doesn't clobber any registers (except the return value in al), so you don't need to mov dx, ax inside the loop. (edit: yes you do, since you need to alternate spaces and digits if you're printing one byte at a time).

    Using AH=09h to write a whole string would mean you could construct it efficiently and then print the whole thing. e.g.

        ;; Not debugged or tested (I don't keep DOS around...)
        ;; So I may have gotten some 2-character constants in the wrong order
        sub    sp, 22      ; reserve space (slightly more than necessary because I didn't debug or even test this)
        mov    di, sp
        mov    ax, '0 '
    .l1:
        stosw               ; store digit and trailing space into [edi+=2]
        inc    al
        cmp    al, '9'
        jle   .l1
    
              ; note that NASM doesn't process \ escapes, but MASM does
        mov    word [di], '\n$'   ; newline and DOS end-of-string marker
        mov    dx, sp             ; dx=input param = start of our buffer
        ; this only works if DS=SS, I guess.  Yay segments.
        mov    ah, 09h            ; DOS write string syscall
        int    21h
        ...
        add    sp, 22             ; release the stack buffer
    
        ...
    

    Note that this code doesn't use a static buffer (bss or data section), unlike most asm examples. This is probably because of segments. Don't spend much time learning about segments, they're not useful for modern programs under modern OSes. See the wiki.

    Also note that it doesn't use loop, because that's slow.

    I could have created the string on the stack with push, but that's maybe more confusing and something you'd never see a compiler do. With push, it would be something like

        push   '\n$'
        mov    ax, '9 '
    .l1:
        push   ax       ; like stosw in reverse, but with SP instead of DI
        dec    al
        cmp    al, '0'
        jge    .l1
    
        ... make the system call with dx=sp
    

    This leaves a trailing space after the 9, though.