I'm trying to understand assembly. Today's topic is: "Storing and incrementing int variables and printing numbers" :)
So here's my code
dane segment
count db 0
dane ends
code segment
start:
inc byte ptr ds:[count]
inc byte ptr ds:[count]
inc byte ptr ds:[count]
mov dl,ds:[count]
mov ah,2
int 21h
mov ah,4ch
int 21h
code ends
end start
When I compile and run, I got this error:
It only happens when count
is incremented more than once.
What wrong am I doing?
Can somebody explain why I can't simply write:
inc count
Also, why I have to put byte ptr
when incrementing values, but not if I copy it to dl
register?
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