I'm working with TASM (in DosBOX emulator).
I'm a beginner and I don't know much yet.
Below is my full code. The problem is that it prints out not just expected output (25 + 10 = 35 and 25 - 10 = 15) but also some rubbish and the program freezes:
SSEG segment stack
db 256 dup(0)
SSEG ends
DSEG segment
num1 dw 25
num2 dw 10
new_line db 0dh,0ah,'$'
msg_add db '25 + 10 = ','$'
msg_sub db '25 - 10 = ','$'
DSEG ends
CSEG segment
assume cs:CSEG,ds:DSEG,ss:SSEG
begin:
mov ax, DSEG
mov ds, ax
; ADD
mov ah, 09h
mov dx, offset msg_add
int 21h
mov ax, num1
mov bx, num2
add ax, bx
mov ax, ax
call print_number
; SUB
mov ah, 09h
mov dx, offset msg_sub
int 21h
mov ax, num1
mov bx, num2
sub ax, bx
mov ax, ax
call print_number
print_number proc
mov si,10
mov cx,0
a:
mov dx,0
div si
add dx,'0'
push dx
inc cx
cmp ax,0
jnz a
aa:
pop dx
mov ah,02h
int 21h
loop aa
mov ah, 09h
mov dx, offset new_line
int 21h
ret
print_number endp
mov ah,4ch
int 21h
CSEG ends
end begin
I tried different approaches of passing arguments into the function. To minmize the code I list only ADD (it's the same logic with SUB)
- by stack
mov ah, 09h
mov dx, offset msg_add
int 21h
mov ax, num1
mov bx, num2
add ax, bx
push ax
call print_number
I tried both popping and pushing of ax register in print_number
popping:
print_number proc
pop ax
mov si,10
mov cx,0
a:
mov dx,0
div si
add dx,'0'
push dx
inc cx
cmp ax,0
jnz a
aa:
pop dx
mov ah,02h
int 21h
loop aa
mov ah, 09h
mov dx, offset new_line
int 21h
ret
print_number endp
pushing:
print_number proc
push ax
mov si,10
mov cx,0
a:
mov dx,0
div si
add dx,'0'
push dx
inc cx
cmp ax,0
jnz a
aa:
pop dx
mov ah,02h
int 21h
loop aa
mov ah, 09h
mov dx, offset new_line
int 21h
ret
print_number endp
- By registers (not sure if I did it right)
It's as in the first code of the question
; ADD
mov ah, 09h
mov dx, offset msg_add
int 21h
mov ax, num1
mov bx, num2
add ax, bx
mov ax, ax
call print_number
print_number proc
mov si,10
mov cx,0
a:
mov dx,0
div si
add dx,'0'
push dx
inc cx
cmp ax,0
jnz a
aa:
pop dx
mov ah,02h
int 21h
loop aa
mov ah, 09h
mov dx, offset new_line
int 21h
ret
print_number endp
But every code doesn't work properly.
I expect just two following lines:
25 + 10 = 35
25 - 10 = 15
With every approach it also prints out rubbish and the program freezes.
How can I fix that?
1 Answer 1
Procedure for printing numbers doesn't work
mov ax, ax call print_number <--- Here program should end print_number proc mov si,10
The procedure for printing numbers works fine, but immediately after printing the line 25 - 10 = 15, the program should have terminated. Because the mention of proc does not create a barrier for the CPU, instead the execution simply continued on the following lines where firstly a 'random' number got printed and then the real problems began because the ret instruction that ends the print_number procedure had no sensible return address on the stack. That's the kind of thing that can freeze a program...
Like Nassau wrote in a comment the solution is:
call print_number
mov ax, 4C00h
int 21h ; DOS.Terminate
; -------------------
; IN (ax)
print_number proc
mov si, 10
Your attempts at solving the issue
push ax ; (35) call print_number ... print_number proc pop ax mov si, 10 ... ret
This can't work because the pop ax will not retrieve the number (35), but rather the return address that the call instruction placed on the stack. Later, the ret instruction will interpret (35) as an address to return to, but, as you understand, it is not an address at all.
push ax call print_number ... print_number proc push ax mov si, 10 ... ret
This can't work because the second push ax will force the ret instruction to return to an incorrect address. Moreover both the pushed argument and the correct return address remain on the stack, and so stack overflow is to be expected at some time in the future.
mov ax, ax call print_number ... print_number proc mov si, 10
This is correct but the mov ax, ax instruction doesn't do anything useful. It just wastes 2 bytes and a small amount of time.
mov ah,4ch, int 21hbeforeprint_number proc. This service properly ends program and returns control to the system. In your case code runs throughprint_number procso that's why you see mess on the screen.aa:...loop aaloop so it's just going to print stuff foreverprint_numbercx = 0, ina:cxis incremented two times and inaa:loop aadecrementscx.intonly pushesflags,csandip. DOS API specifies what registers are used in every function. Here02h,09hand4chdon't need cx and also after interrupt cx is preserved. Well, my debugger says so.