Edit: rewrote and added text, added code (works in MASM 6.11):
In x86 assembbly you need to specify the size of the memory operand for instructions in which there would be ambiguity otherwise. You have to tell the assembler the size of the operand with byte ptr
, word ptr
etc. For that reason inc byte ptr ds:[count]
needs byte ptr
. inc word ptr ds:[count
is different instruction.
mov dl,ds:[count]
do not need byte ptr
, because dl
is a 8-bit register and therefore the size of the memory operand is always the same, a byte (8 bits).
To print characters, you need to first convert the number into a string (or a single character for numbers less than 10). Otherwise you are printing control character ETX (see ASCII table) that has ASCII code 3. For numbers less than 10, printing in decimal is trivial, just add '0' (30h
), like this:
mov dl,ds:[count]
add dl,'0' ; add dl,30h
Printing in decimal in x86 assembly is a asked quite often, see for example Is this code correct (Number plus number, then print the result) to get the idea.
Edit: EXE files need also a stack segment.
DOS EXE files need to have a stack segment. Assembling with MASM 6.11 does not give any warnings or errors, basically with dosexe.asm
(replace dosexe.asm to your assembly code file name).
But linking with ML (ml dosexe.obj
) gives the following warning:
LINK : warning L4021: no stack segment
So, a stack segment needs to be added, add the following lines to top of the source.
.model small
.stack 4096
There was also some problem with data segment definition, I fixed that too.
The entire fixed assembly code could be something like this (works in MASM 6.11):
.model small
.stack 4096
.data
count db 0
.code
start:
mov ax,seg count
mov ds,ax
inc byte ptr ds:[count]
inc byte ptr ds:[count]
inc byte ptr ds:[count]
; this code does the printing in decimal without needing to reverse
; the string, by dividing the divisor. 100/10 = 10
mov bl,100 ; original divisor.
mov al,ds:[count]
print_loop:
xor ah,ah ; clear top 8 bits of the dividend (in ax).
div bl ; divide ax by bl. quotient in al, remainder in ah.
mov dl,al ; the value to be printed with ah = 2, int 21h
mov al,ah ; remainder gets divided in the next loop.
test dl,dl ; check if number is zero
jz not_print ; don't print leading zeros.
add dl,'0' ; convert to ASCII numeric characters range.
; '0' = 0x30 = 48
push ax
mov ah,2
int 21h ; print the value, according to Ralf Brown's
pop ax ; interrupt list returns al.
not_print:
push ax
mov al,bl
xor ah,ah
mov bl,10 ; divide the divisor by 10.
div bl
mov bl,al ; the new divisor.
pop ax
test bl,bl
jnz print_loop
mov ah,4ch
int 21h
end start