org 0x0100
jmp start
; Declare variables
input1: db 0
input2: db 7
input3: db 9
input4: db 1
message1: db 'The value of AX, BX and CX is: '
length: dw 31
start:
; Push output variables with random values
push 3 ; Random value 1
push 5 ; Random value 2
push 7 ; Random value 3
call my_subroutine
; Retrieve output variables
pop cx ; Retrieve output into CX
pop bx ; Retrieve output into BX
pop ax ; Retrieve output into AX
;Display the output values
call display
; Exit program
mov ax, 0x4c00
int 0x21
my_subroutine:
; Save registers
push ax
push bx
push si
push di
push cx
; Local variables (initialized with random values)
local1: dw 1
local2: dw 2
local3: dw 3
local4: dw 4
local5: dw 5
; Example operations (just random logic for demonstration)
mov ax, [input1] ; Load first input
add ax, [local1] ; Add local variable
mov bx, [input2] ; Load second input
sub bx, [local2] ; Subtract local variable
; Push results
;push ax ; Push first output (AX)
;push bx ; Push second output (BX)
;mov cx, word [input3]
;push cx ; Push third output (local variable)
; Restore registers
pop cx ; Pop last pushed value into CX
pop bx ; Restore BX
pop ax ; Restore AX
pop di ; Restore DI
pop si ; Restore SI
ret ; Return to the caller
cls:
push es
push ax
push di
mov ax, 0xB800
mov es, ax
mov di, 0
allSpace:
mov word [es:di], 0x0720
add di, 2
cmp di, 4000
jne allSpace
pop di
pop ax
pop es
ret
convert_num_to_string:
push bp
mov bp, sp
push es
pusha
mov ax, 0xb800
mov es, ax
mov ax, [bp+4]
mov bx, 10
mov cx, 0
nextdigit:
mov dx, 0
div bx
add dl, 0x30
push dx
inc cx
cmp ax, 0
jnz nextdigit
nextpos:
pop dx
mov dh, 0x07
mov [es:di], dx
add di, 2
loop nextpos
popa
pop es
pop bp
ret 2
display_message:
push bp
mov bp, sp
push es
push ax
push bx
push cx
mov ax, 0xb800
mov es, ax
mov si, [bp+6]
mov cx, [bp+4]
mov ah, 0x07
printAllChar:
mov al, [si]
mov [es:di], ax
add di, 2
add si, 1
loop printAllChar
pop cx
pop bx
pop ax
pop es
pop bp
ret 4
display:
call cls
mov di, 0
push message1
push word [length]
call display_message
mov di, 62
push ax
call convert_num_to_string
mov di, 66
push bx
call convert_num_to_string
mov di, 70
push cx
call convert_num_to_string
ret
my_subroutine:
In the subroutine above, when I push my result onto the stack, the control does not return to below call my_subroutine
, but rather an infinite loop runs.
You are required to write a subroutine in assembly language that:
- Takes 4 input variables (which will be the digits from your roll number i.e 22F-3440 , 3440 are the 4 inputs).
- Returns 3 output variables. These output variables are pushed (with random values) before the input variables in the main.
- Creates 5 local variables inside the function. Initialized with random values from 1 to 10.
- Uses the registers AX, BX, SI, DI, and CX to perform operations, but save and restore these registers before and after use to avoid overwriting their original values.
- The outputs must be popped into AX, BX, and CX after the subroutine returns.
- Display these to the console.
; Local variables (initialized with random values) local1: dw 1 local2: dw 2 local3: dw 3 local4: dw 4 local5: dw 5
These are not local variables! They're just as global as those other variables that you've declared (input, message, length). They only seem local because their name says so and because you've written them inside the my_subroutine subroutine. In many assemblers you could at least make these variables 'accessible local-only', by prepending their names with a dot: .local1: dw 1
. But this is still not ideal because they will continue to occupy their memory for as long as your program runs.
Additionally because of their emplacement in the execution path of your program, the cpu will execute these data bytes with possible disastrous results. In your main you knew that you had to jump around the data declarations with that jmp start
. So, you could have used something similar here.
Anyway, for your task the best solution is to place the local variables on the stack. See the code example below.
; Save registers push ax push bx push si push di push cx ... ; Restore registers pop cx pop bx pop ax pop di pop si ret
You must restore the registers in the reverse order to how you pushed them before. Except for CX, this is not the case here!
- Returns 3 output variables. These output variables are pushed (with random values) before the input variables in the main.
This is an important sentence and my take on it, is that a total of 7 values get pushed on the stack prior to calling the subroutine. Since unlike for the local variables, no limit was placed on the random values, you could save a few bytes and just push whatever (random) value there happens to be in the AX, BX, and CX registers. Alternatively, just consider the stack memory is already filled with such 'random' values, and thus a mere sub sp, 6
will reserve the space for those 3 outputs:
; Push output variables with random values
push cx ; (1) alternative: sub sp, 6 ; (1)(2)(3)
push bx ; (2)
push ax ; (3)
; Push input variables with digits from roll number
push 1 ; 4th digit
push 9 ; 3rd digit
push 7 ; 2nd digit
push 0 ; 1st digit
call my_subroutine
pop ax ; (3)
pop bx ; (2)
pop cx ; (1)
Stack layout once we're inside the subroutine:
1 2 3 4 5 CX DI SI BX AX BP RET 0 7 9 1 ? ? ?
^ ^ ^ ^ ^ ^ ^ ^
| [bp-18] [bp] | [bp+6] | | [bp+16]
[bp-20] [bp+4] | [bp+14]
[bp+12]
my_subroutine:
push bp
mov bp, sp
push ax ; Save registers
push bx
push si
push di
push cx
push 5 ; Local variables (initialized with random values)
push 4
push 3
push 2
push 1
; Example operations (just random logic for demonstration)
mov ax, [bp+4] ; Load first input
add ax, [bp-20] ; Add local variable
mov bx, [bp+6] ; Load second input
sub bx, [bp-18] ; Subtract local variable
...
mov [bp+12], ax ; "Push" results
mov [bp+14], bx
mov [bp+16], cx
add sp, 10 ; Release local variables
pop cx ; Restore registers
pop di
pop si
pop bx
pop ax
pop bp
ret 8 ; Remove the 4 inputs
display_message currently forgets to preserve SI and DI, but needlessly preserves BX. Also it's a bit strange to see DI as a register-input to this routine together with a couple of stack-inputs. I think 3 stack-inputs OR 3 register-inputs would be nicer...