Moe
Moe

Reputation: 555

Error while printing a string from assembly code

I'm new to assembly and the course that I follow uses EMU8086. I wrote this code to print Testing and the ASCII code of 50 which is number 2 but it only prints Testing and ignores the rest. What's wrong?

.model tiny
.code

org 100h


main proc

    mov ah, 09h
    mov dx, offset msg
    int 21h 
    mov ah, 4ch
    mov dx ,0  
    mov dl, 2
    add dl, 48
    int 21h      

endp

msg db "Testing$"

end main

After reading the comments from @500 - Internal Server Error, I updated my code to this:

.model tiny
.code

org 100h


main proc

    mov ah, 09h
    mov dx, offset msg
    int 21h 
    mov dl, 2
    add dl, 48
    int 21h      

endp

msg db "Testing$"

end main

It still isn't working, so what's wrong?

Upvotes: 3

Views: 1756

Answers (2)

Michael Petch
Michael Petch

Reputation: 47563

The DOS interrupt INT 21h/AH=9h doesn't take a character value to print, it takes the memory offset to the beginning of a $ terminated string to print.

DOS 1+ - WRITE STRING TO STANDARD OUTPUT

AH = 09h

DS:DX -> '$'-terminated string

Return:

AL = 24h (the '$' terminating the string, despite official docs which state that nothing is returned) (at least DOS 2.1-7.0 and NWDOS)

If you want to print out a single character with INT 21h/AH=9h then you'll need to move the value into a buffer that is terminated with a $ sign. You then pass the address of that buffer into INT 21h/AH=9h. Based on your second example something like this should work:

.model tiny
.code
org 100h

main proc
    mov ah, 09h             ; DOS Interrupt ah=9h print $ terminated string
    mov dx, offset msg      ; Address of msg 
    int 21h                 ; Int 21h/ah=9h Print msg 
    mov outchar, 48+2       ; Move ASCII val for `2` to outchar buffer
    mov dx, offset outchar  ; Address of the $ terminated outchar buffer in DX
    int 21h                 ; AH is still 9h, so this prints $ terminated string

    mov ax, 4c00h           ; Exit program with return value 0
    int 21h    
endp

msg db "Testing$"           ; msg string
outchar db ?, "$"           ; output buffer for single character terminated with $

end main

Instead of mov outchar, 48+2 you could just use the ASCII value like this:

mov outchar, '2'

Alternatively you could do it with a single call to INT 21h/AH=9h by placing the character you want into the middle of an output buffer:

main proc
    mov outchar, '2'    ; Place the ASCII value for '2' in the output buffer
    mov ah, 09h         
    mov dx, offset msg  
    int 21h             ; Print $ terminated string starting at `msg`
    mov ax, 4c00h
    int 21h             ; Exit with error code 0
endp

msg     db "Testing"
outchar db ?, "$"

The reason this works is because INT 21h/AH=9h will blindly print everything it finds starting at offset msg until it finds a $ terminating character. We effectively do the substitution of the character at outchar first so that when INT 21h/AH=9h is executed it will encounter Testing2$ in memory.

Once it reaches the $ it will stop printing so the output would look like:

Testing2


You also have the option of using two different DOS (INT 21h) interrupts. While INT 21h/AH=9h prints a $ terminated string, INT 21h/AH=2h displays a single character:

DOS 1+ - WRITE CHARACTER TO STANDARD OUTPUT

AH = 02h

DL = character to write

Return: AL = last character output (despite the official docs which state nothing is returned) (at least DOS 2.1-7.0)

You could code your program to display the msg string as you did, but then you can use INT 21h/AH=2h to display a single character. Your code could then look like this:

.model tiny
.code
org 100h

main proc
    mov ah, 09h             ; DOS Interrupt ah=9h print $ terminated string
    mov dx, offset msg      ; Address of msg 
    int 21h                 ; Int 21h/ah=9h Print msg 
    mov ah, 02h             ; DOS interrupt ah=2h print single character
    mov dl, '2'             ; DL = ASCII value of character to print
    int 21h                 ; Int 21h/ah=2h print single character in DL 

    mov ax, 4c00h           ; Exit program with return value 0
    int 21h    
endp

msg db "Testing$"           ; msg string

end main

Upvotes: 1

Your second code is almost fine, you only forgot the service number in ah to tell int 21h what to do :

.model tiny
.code

org 100h


main proc

    mov ah, 09h
    mov dx, offset msg
    int 21h 

    mov ah, 2          ;<==== AH=2 : INT 21H WILL DISPLAY CHARACTER IN DL.
    mov dl, 2
    add dl, 48
    int 21h      

endp

msg db "Testing$"

end main

Upvotes: 1

Related Questions