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
Problema principal emmy_subroutine:
Na sub-rotina acima, quando eu envio meu resultado para a pilha, o controle não retorna ao início, mas sim um loop infinito é executado.
A propósito, aqui está a questão que estou tentando resolver:
Você precisa escrever uma sub-rotina em linguagem assembly que:
- Aceita 4 variáveis de entrada (que serão os dígitos do seu número de registro, ou seja, 22F-3440, 3440 são as 4 entradas).
- Retorna 3 variáveis de saída. Essas variáveis de saída são empurradas (com valores aleatórios) antes das variáveis de entrada no principal.
- Cria 5 variáveis locais dentro da função. Inicializado com valores aleatórios de 1 a 10.
- Usa os registradores AX, BX, SI, DI e CX para executar operações, mas salva e restaura esses registradores antes e depois do uso para evitar sobrescrever seus valores originais.
- As saídas devem ser inseridas em AX, BX e CX após o retorno da sub-rotina.
- Exiba-os no console.
Essas não são variáveis locais! Elas são tão globais quanto as outras variáveis que você declarou ( input , message , length ). Elas só parecem locais porque o nome delas diz isso e porque você as escreveu dentro da subrotina my_subroutine . Em muitos assemblers você poderia pelo menos tornar essas variáveis 'acessíveis somente localmente', adicionando um ponto aos seus nomes:
.local1: dw 1
. Mas isso ainda não é o ideal porque elas continuarão ocupando a memória delas enquanto seu programa estiver em execução.Além disso, por causa da colocação delas no caminho de execução do seu programa, a CPU executará esses bytes de dados com possíveis resultados desastrosos. No seu main você sabia que tinha que pular as declarações de dados com isso
jmp start
. Então, você poderia ter usado algo similar aqui.De qualquer forma, para sua tarefa a melhor solução é colocar as variáveis locais na pilha. Veja o exemplo de código abaixo.
Você deve restaurar os registradores na ordem inversa de como você os empurrou antes. Exceto para CX, esse não é o caso aqui!
Esta é uma frase importante e minha opinião sobre ela é que um total de 7 valores são colocados na pilha antes de chamar a subrotina. Como, diferentemente das variáveis locais, nenhum limite foi colocado nos valores aleatórios, você pode economizar alguns bytes e simplesmente colocar qualquer valor (aleatório) que esteja nos registradores AX, BX e CX. Como alternativa, considere que a memória da pilha já está preenchida com esses valores "aleatórios" e, portanto, um mero
sub sp, 6
reservará o espaço para essas 3 saídas:Layout da pilha quando estamos dentro da sub-rotina:
display_message atualmente esquece de preservar SI e DI, mas preserva BX desnecessariamente. Também é um pouco estranho ver DI como uma entrada de registro para essa rotina junto com algumas entradas de pilha. Acho que 3 entradas de pilha OU 3 entradas de registro seriam melhores...