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:
在上面的子程序中,当我将结果推送到堆栈时,控制不会返回开始,而是运行无限循环
顺便说一下,这是我试图解决的问题:
您需要用汇编语言编写一个子程序:
- 接受 4 个输入变量(即您的学号中的数字,即 22F-3440,3440 是 4 个输入)。
- 返回 3 个输出变量。这些输出变量(使用随机值)被推送到主函数中的输入变量之前。
- 在函数内部创建 5 个局部变量。使用 1 到 10 之间的随机值进行初始化。
- 使用寄存器 AX、BX、SI、DI 和 CX 执行运算,但在使用前后保存和恢复这些寄存器,以避免覆盖其原始值。
- 子程序返回后,必须将输出弹出到 AX、BX 和 CX 中。
- 将这些显示到控制台。
这些不是局部变量!它们和您声明的其他变量( input、message、length )一样是全局变量。它们看起来只是局部的,因为它们的名称是这样的,并且因为您将它们写在了my_subroutine子例程内。在许多汇编程序中,您至少可以通过在这些变量的名称前面加上一个点:
.local1: dw 1
,使这些变量“仅在本地可访问”。但这仍然不是理想的选择,因为只要您的程序运行,它们就会继续占用内存。此外,由于它们位于程序的执行路径中,CPU 将执行这些数据字节,可能会导致灾难性的后果。在您的主函数中,您知道必须使用那个来跳过数据声明
jmp start
。所以,您可以在这里使用类似的东西。无论如何,对于您的任务,最好的解决方案是将局部变量放在堆栈上。请参阅下面的代码示例。
您必须按照与之前推送寄存器相反的顺序恢复寄存器。除了 CX,这里不是这种情况!
这句话很重要,我的看法是,在调用子程序之前,总共有7 个值被推送到堆栈上。由于与局部变量不同,随机值没有限制,因此您可以节省几个字节,只需推送 AX、BX 和 CX 寄存器中碰巧存在的任何(随机)值即可。或者,只需考虑堆栈内存已经充满了这样的“随机”值,因此只需
sub sp, 6
为这 3 个输出保留空间:进入子程序后的堆栈布局:
display_message当前忘记保存 SI 和 DI,但毫无必要地保存了 BX。此外,将 DI 与几个堆栈输入一起视为此例程的寄存器输入有点奇怪。我认为 3 个堆栈输入或 3 个寄存器输入会更好...