No output from 8086 program when running ml program.asm in DOSBox - debugging

I got this code from the Geeks-for-Geeks site, but there were lots of indentation errors, I changed the code to the following but, when running the code using MASM and DOSBox it's giving no output.
The Output I should get, According to the site I should get 20 but I get nothing, the code is saved as pro.asm, and I'm using DOSBox version 0.74.
For getting the o/p in the DOSBox I did,
mount c c:\8086
c:
ml pro.asm
Code:
;8086 program to convert a 16-bit decimal number to octal
.MODEL SMALL
.STACK 100H
.DATA
d1 dw 16
.CODE
MAIN PROC FAR
MOV ax,#DATA
MOV ds,ax
;load the value stored in variable d1
MOV ax, d1
;convert the value to octal
;print the value
CALL PRINT
;interrupt to exit
MOV AH,4CH
INT 21H
MAIN ENDP
PRINT PROC
;initialize count
MOV cx,0
MOV dx,0
label1: ;if ax is zero
cmp ax,0
je print1
;initialize bx to 8
mov bx, 8
;divide it by 8 to convert it to octal
div bx
;push it in the stack
push dx
;increment the count
inc cx
;set dx to 0
xor dx,dx
jmp label1
print1: ;check if count is greater than zero
cmp cx,0
je exit
;pop the top of stack
pop dx
;add 48 so that it
;represents the ASCII
;value of digits
add dx,48
;interrupt to print a
;character
mov ah,02h
int 21h
;decrease the count
dec cx
jmp print1
exit : ret
PRINT ENDP
END MAIN
The output I'm getting can be seen below

Your code looks okay. Your screenshot shows you have only assembled and linked the code but not actually run it. To run it type:
pro.exe

Related

How to print an integer stored in a variable

So I have a program in 8086 assembly that allows the user to enter 2 digits, store them in a variable and then print out the number:
data segment
broj db ?
ends
stack segment
dw 128 dup(0)
ends
code segment
mov ax, data
mov ds, ax
mov es, ax
mov ah, 1h
int 21h
sub al, 48d
mov bl, 10d
mul bl
mov broj, al
mov ah, 1h
int 21h
sub al, 48d
add broj, al
mov dl, broj
sub dl, 48d
mov ah, 2h
int 21h
mov ax, 4c00h
int 21h
ends
However whenever I enter a number for example 21 it doesn't give me the number instead it gives me ASCII Code for that value.
Can anyone help?!
However whenever I enter a number for example 21 it doesn't give me the number instead it gives me ASCII Code for that value.
If you feed (input) your program a number that consists of 2 digits, then you'll have to print also 2 digits! Currently your code contains just the one character output function.
First divide the number in broj by 10 giving a quotient (in AL) and a remainder (in AH).
Convert the quotient to character (Add 48) and print it.
Convert the remainder to character (Add 48) and print it.
Example:
mov al, broj
mov ah, 0
mov bl, 10
div bl
add ax, "00"
mov dx, ax
mov ah, 02h
int 21h
mov dl, dh
mov ah, 02h
int 21h

Why does the following 8086 assembly code only display numbers up to 2559?

What am I trying to do ?
I want to get a 16-bit number from the user and print It on the console.
What Is the problem ?
Well my code works fine If the number entered Is less than 2600 but the moment I enter 2600 It displays "40" and for 2601 "41" and so on. Shouldn't It display numbers up to 65535 ? Because I am storing the value In the bx register which Is 16-bit and which can store at most 65535. Then why only 2559 ?
My code:
.model small
.data
msg db 10,13,'Enter a 16bit number: $'
newline db 10,13,'$'
.code
main:
mov ax, #data
mov ds, ax
mov cl, 10
mov bx, 0
mov ah, 09h
lea dx, msg
int 21h
call get16bitNum
mov ah, 09h
lea dx, newline
int 21h
mov ax, '$'
push ax
mov ax, bx
store:
div cl
cmp al, 0
mov bh, 0
mov bl, ah
push bx
je continue
mov ah, 0
jmp store
continue:
pop ax
cmp ax, '$'
je ext
mov bx, ax
mov ah, 02h
mov dx, bx
add dx, 48
int 21h
jmp continue
ext:
mov ah, 04ch
int 21h
proc get16bitNum
aggregate:
mov ah, 01h
int 21h
cmp al, 13
je return
mov ah, 0
sub al, 48
mov dx, bx
mov bx, ax
mov ax, dx
mul cl
add bx,ax
jmp aggregate
return:
ret
endp
end main
You don't actually retrieve a 16-bit number!
You keep the desired input in BX, and so you need to multiply the whole of BX by 10. You do this using a word sized multiplication.
proc get16bitNum
aggregate:
mov ah, 01h
int 21h
cmp al, 13
je return
mov ah, 0
sub al, 48 ;AX is 0 to 9
xchg ax, bx ;New digit temporarily in BX
mov cx, 10
mul cx ;Product is in DX:AX, but we won't use DX!
add bx ,ax ;Add new digit
jmp aggregate
return:
ret
You don't display the 16-bit number
The procedure to convert the number into text will definitely need to use the word sized division.
For an excellent explanation on how to do this see this recent post Displaying numbers with DOS. It explains in great detail everything you need to know about converting numbers. It even uses the same technique of pushing some value in the stack (You used a $ character for this) to know where the number ends.
ps. If you find the info in the linked post useful don't hesitate to upvote it. (Of course I hope you find my answer useful too!)
8 bit div produces 8 bit quotient and remainder.
When you divide 2600 by 10 you get an 8 bit quotient, losing higher bits.
You should use 16 bit division.

Algorithm to assembly x86?

I have been for some days trying to translate an algorithm to assembly x86, and I did it. However I would like to print the final result that it is saved in "tmp", what instruction can I use? (I'm Spanish so I'm sorry if I say something wrong in English).
This is my algorithm:
tmp = NOT(L0)
tmp = tmp AND L1
tmp = NOT(NOT(tmp) OR NOT(L2))
tmp = NOT(tmp OR NOT(L3))
tmp = NOT(tmp + NOT(L4))
if (tmp == L5)
licence = correct
else
licence = incorrect
And this is it in assembly:
LicenceCorrect PROC
push ebp
mov ebp,esp
push ebx
push ecx
push edx
mov ebx, [ebp+8]
mov edx,[ebx]
mov ecx,edx
not ecx
mov edx,[ebx+4]
and ecx,edx
mov edx,[ebx+8]
not edx
not ecx
or ecx,edx
not ecx
mov edx,[ebx+16]
not edx
or ecx,edx
not ecx
;if
mov edx,[ebx]
cmp ecx,edx
jne cons
mov al,0
jmp next
cons:
mov al,1
next:
pop edx
pop ecx
pop ebx
pop ebp
ret
LicenceCorrect ENDP
END
Next code displays a number in AX (made with EMU8086). What MissPaper must do now is insert your procedure (LicenseCorrect) at the end of next code, and call it after "call dollars", then assign the value to AX (remove "12345").
Here it is for 32 bits:
.model small
.stack 100h
.data
buffer db 6 dup(?)
.code
start:
;INITIALIZE DATA SEGMENT.
mov ax, #data
mov ds, ax
;FIRST, FILL BUFFER WITH '$' (NECESSARY TO DISPLAY).
mov si, offset buffer
call dollars
;SECOND, CONVERT NUMBER TO STRING.
mov ax, 12345
mov si, offset buffer
call number2string
;THIRD, DISPLAY STRING.
mov dx, offset buffer
call printf
;FINISH PROGRAM.
mov ax, 4c00h
int 21h
;-----------------------------------------
;PARAMETER : DX POINTING TO '$' FINISHED STRING.
printf proc
mov ah, 9
int 21h
ret
printf endp
;------------------------------------------
;FILLS VARIABLE WITH '$'.
;USED BEFORE CONVERT NUMBERS TO STRING, BECAUSE
;THE STRING WILL BE DISPLAYED.
;PARAMETER : SI = POINTING TO STRING TO FILL.
dollars proc
mov cx, 6
six_dollars:
mov bl, '$'
mov [ si ], bl
inc si
loop six_dollars
ret
dollars endp
;------------------------------------------
;CONVERT A NUMBER IN STRING.
;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE
;THEM IN STACK, THEN EXTRACT THEM IN REVERSE
;ORDER TO CONSTRUCT STRING (STR).
;PARAMETERS : AX = NUMBER TO CONVERT.
; SI = POINTING WHERE TO STORE STRING.
number2string proc
mov bx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
mov cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
cycle1:
mov dx, 0 ;NECESSARY TO DIVIDE BY BX.
div bx ;DX:AX / 10 = AX:QUOTIENT DX:REMAINDER.
push dx ;PRESERVE DIGIT EXTRACTED FOR LATER.
inc cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
cmp ax, 0 ;IF NUMBER IS
jne cycle1 ;NOT ZERO, LOOP.
;NOW RETRIEVE PUSHED DIGITS.
cycle2:
pop dx
add dl, 48 ;CONVERT DIGIT TO CHARACTER.
mov [ si ], dl
inc si
loop cycle2
ret
number2string endp
end start
Now the 64 bits version (for much bigger numbers in EAX), made with GUI Turbo Assembler x64 (http://sourceforge.net/projects/guitasm8086/):
.model small
.586
.stack 100h
.data
buffer db 11 dup(?)
.code
start:
;INITIALIZE DATA SEGMENT.
mov ax, #data
mov ds, ax
;FIRST, FILL BUFFER WITH '$' (NECESSARY TO DISPLAY).
mov esi, offset buffer
call dollars
;SECOND, CONVERT NUMBER TO STRING.
mov eax, 1234567890
mov esi, offset buffer
call number2string
;THIRD, DISPLAY STRING.
mov dx, offset buffer
call printf
;FINISH PROGRAM.
mov ax, 4c00h
int 21h
;-----------------------------------------
;PARAMETER : DX POINTING TO '$' FINISHED STRING.
printf proc
mov ah, 9
int 21h
ret
printf endp
;------------------------------------------
;FILLS VARIABLE WITH '$'.
;USED BEFORE CONVERT NUMBERS TO STRING, BECAUSE
;THE STRING WILL BE DISPLAYED.
;PARAMETER : ESI = POINTING TO STRING TO FILL.
dollars proc
mov cx, 11
six_dollars:
mov bl, '$'
mov [ esi ], bl
inc esi
loop six_dollars
ret
dollars endp
;------------------------------------------
;CONVERT A NUMBER IN STRING.
;ALGORITHM : EXTRACT DIGITS ONE BY ONE, STORE
;THEM IN STACK, THEN EXTRACT THEM IN REVERSE
;ORDER TO CONSTRUCT STRING (STR).
;PARAMETERS : EAX = NUMBER TO CONVERT.
; ESI = POINTING WHERE TO STORE STRING.
number2string proc
mov ebx, 10 ;DIGITS ARE EXTRACTED DIVIDING BY 10.
mov cx, 0 ;COUNTER FOR EXTRACTED DIGITS.
cycle1:
mov edx, 0 ;NECESSARY TO DIVIDE BY EBX.
div ebx ;EDX:EAX / 10 = EAX:QUOTIENT EDX:REMAINDER.
push dx ;PRESERVE DIGIT EXTRACTED (DL) FOR LATER.
inc cx ;INCREASE COUNTER FOR EVERY DIGIT EXTRACTED.
cmp eax, 0 ;IF NUMBER IS
jne cycle1 ;NOT ZERO, LOOP.
;NOW RETRIEVE PUSHED DIGITS.
cycle2:
pop dx
add dl, 48 ;CONVERT DIGIT TO CHARACTER.
mov [ esi ], dl
inc esi
loop cycle2
ret
number2string endp
end start
I didn't add your procedure because it uses the stack and I don't know what values to push before calling it.

First macro assembler program, can't figure our unhandled exception

This is my first assembler program in masm32. Using vis studio 2012. And this is just one procedure in a program to convert input into an ascii chart with decimal, hex and ascii output. I've been trying to figure this out for 8 hours, and I know it's going to be something really simple.
It gets through all the computation, but during the pop and return phase it crashes into an unhandled exception when accessing the EIP(i think). Also, all my registers are set to 0 except ebx and I don't know why, but it may have something to do with it.
This is just the procedure to convert from the input string to a decimal value.*
My inputStr is:
inputStr db 16 DUP(0)
.code
main proc
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx
lea esi, outputStr1
call PrintString
lea esi, inputStr
call GetString
call StrtoNum
invoke ExitProcess, 0 ;****This is the next line when it crashes***
main endp
StrtoNum proc ;going to hex first
pushad
pushfd
mov bl, 1 ;mov 1 into bl for later multiplying
whilemorechar:
mov al,byte ptr [esi]
cmp al, 0 ;stuff
je ConvertDone ;if null then we are done here
;esi is pointing to the string to be converted
;cmp bl,0
;jnz decrement
cmp al, 0h
je ConvertDec
sub al, 30h ;get first string byte to dec number 0-9
push ax ;push last digit to stack
inc esi ;gets to next string byte
inc cl ;make note of decimal position in string
jmp whilemorechar ;jump for next place in string
ConvertDec: ;reverse is done, now turn into decimal number
cmp cl, 0 ;compare counter to 0
jz ConvertDone ;if counter is 0, start comparing numbers
pop ax ;pop last on stack
mul bl ;multiply place value by input byte
add dx, ax ;add decimal value into dl
mov al, 10d ;move 10 into al
mul bx ;multiply 10 and bl value to get next
mov bx, ax ;mov decimal place into bl for next loop
dec cl ;decrement counter
jmp ConvertDec ;loop through again for next decimal place
ConvertDone:
mov ebx, 0
popfd ;pop flags
popad ;pop registers
ret ;return to caller
StrtoNum endp

TASM SIMPLE LOOP implemention

I just want too write simple .asm code for TASM that work as for in C++
int t=2;
for(int i=0;i<2;i++)
t=t+(i-1)*7*t;
How can I implement it with TASM?
This will loop from 1 to 100 in 8086 TASM:
.MODEL SMALL
.STACK 100h
.DATA
Finished DB 10, 13, 'Loop x 100 finished. Congratulations! $', 10, 13
.CODE
MAIN PROC
MOV AX, #data ; Required at the start of every program (inside your main procedure, from what I've seen)
MOV DS, AX
MOV CX, 100 ; Set CX to 100
MOV BX, 0 ; Counter (for double-verification, I guess...lol)
StrtLoop: ; When a loop starts, it does CX-- (subtracts 1 from CX)
INC BX ; This does BX++, which increments BX by 1
LOOP StrtLoop ; Go back to StrtLoop label
CMP BX, 100 ; Compare BX to 100...
JE DispMsg ; Jump-if-Equal...CMP BX, 100 sets flags, and if they are set,
; JE will Jump you to DispMsg (to get "congratulations" message).
JMP SkipMsg ; Jump to the SkipMsg label (so you don't see the "congratulations" message).
DispMsg: ; If BX = 100, you JE here.
MOV AH, 09H ; Displays the message stored in the defined byte "Finished"
MOV DX, OFFSET Finished
INT 21H
SkipMsg: ; If BX != 100, you JMP here.
MOV AL, 0h ; Op code to exit to DOS from the assembler.
MOV AH, 4CH
INT 21H
MAIN ENDP
END MAIN
I hope it helps. I did the basic loop, so you can do the other bits of your code (and I don't know C++, lol). Good luck! It's hard, but kind of fun at the same time (at least for me).

Resources