2

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:

enter image description here


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)

  1. 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
  1. 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?

Sep Roland
41.3k10 gold badges50 silver badges90 bronze badges
asked Nov 26, 2024 at 10:16
6
  • 3
    Try to move instructions: mov ah,4ch, int 21h before print_number proc. This service properly ends program and returns control to the system. In your case code runs through print_number proc so that's why you see mess on the screen. Commented Nov 26, 2024 at 10:54
  • Looks like you have no way to get out of the aa:...loop aa loop so it's just going to print stuff forever Commented Nov 26, 2024 at 11:02
  • @PeterHull On entry to print_number cx = 0, in a: cx is incremented two times and in aa: loop aa decrements cx. Commented Nov 26, 2024 at 11:26
  • Sorry you're right, I am very rusty on this. But does the int21 corrupt the value of cx, i.e. do you need to push/pop it around the int21? Commented Nov 26, 2024 at 11:49
  • @PeterHull Intel manual says that in real-mode int only pushes flags,cs and ip. DOS API specifies what registers are used in every function. Here 02h, 09h and 4ch don't need cx and also after interrupt cx is preserved. Well, my debugger says so. Commented Nov 26, 2024 at 13:28

1 Answer 1

2

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.

answered Nov 26, 2024 at 18:11
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.