Вопрос или проблема
org 0x0100
jmp start
; Объявление переменных
input1: db 0
input2: db 7
input3: db 9
input4: db 1
message1: db 'Значения AX, BX и CX: '
length: dw 31
start:
; Запись выходных переменных со случайными значениями
push 3 ; Случайное значение 1
push 5 ; Случайное значение 2
push 7 ; Случайное значение 3
call my_subroutine
; Извлечение выходных переменных
pop cx ; Извлечение значения в CX
pop bx ; Извлечение значения в BX
pop ax ; Извлечение значения в AX
; Отобразить выходные значения
call display
; Завершение программы
mov ax, 0x4c00
int 0x21
my_subroutine:
; Сохранение регистров
push ax
push bx
push si
push di
push cx
; Локальные переменные (инициализированные случайными значениями)
local1: dw 1
local2: dw 2
local3: dw 3
local4: dw 4
local5: dw 5
; Пример операций (просто случайная логика для демонстрации)
mov ax, [input1] ; Загрузка первой входной переменной
add ax, [local1] ; Добавление локальной переменной
mov bx, [input2] ; Загрузка второй входной переменной
sub bx, [local2] ; Вычитание локальной переменной
; Запись результатов
;push ax ; Запись первого результата (AX)
;push bx ; Запись второго результата (BX)
;mov cx, word [input3]
;push cx ; Запись третьего результата (локальная переменная)
; Восстановление регистров
pop cx ; Восстановление CX
pop bx ; Восстановление BX
pop ax ; Восстановление AX
pop di ; Восстановление DI
pop si ; Восстановление SI
ret ; Возврат в вызывающую программу
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 после возврата подпрограммы.
- Отображает их на консоли.
Ответ или решение
Чтобы решить проблему передачи значений между подпрограммами в ассемблере, важно правильно использовать стек для хранения и передачи данных. В вашем коде есть несколько ключевых моментов, которые необходимо учесть, чтобы избежать зацикливания программы после вызова подпрограммы. Давайте разберём это подробно.
Понимание работы стека
Стек — это структура данных, работающая по принципу "последний пришёл — первый вышел" (LIFO). При вызове подпрограммы (функции) важно, чтобы:
- Заранее были размещены все необходимые данные, которые мы собираемся передать в подпрограмму, на стеке.
- После завершения выполнения подпрограммы результаты возвращались обратно и корректно извлекались.
Основные шаги для успешной передачи данных в подпрограмму
-
Сохранение регистров: Ваша подпрограмма должна сохранять важные регистры перед тем, как использовать их, и восстанавливать их после завершения. Это необходимо для предотвращения перезаписи значений, используемых в вызывающем коде.
-
Передача аргументов: Используйте стек для передачи параметров в подпрограмму. В вашем случае также следует учитывать, что в стеке будут индивидуальные значения, которые подлежат извлечению.
Улучшенный код подпрограммы
Ниже представлен исправленный вариант вашей подпрограммы my_subroutine
. Здесь акцентируется внимание на правильной передаче и извлечении значений.
my_subroutine:
; Сохранение регистров
push ax
push bx
push cx
push si
push di
; Локальные переменные (инициализированные случайными значениями)
local1: dw 1
local2: dw 2
local3: dw 3
local4: dw 4
local5: dw 5
; Пример операций (демонстрация)
mov ax, [input1] ; Загрузка первого входа
add ax, [local1] ; Сумма с локальной переменной
mov bx, [input2] ; Загрузка второго входа
sub bx, [local2] ; Вычитание локальной переменной
; П Push результат на стек
push ax ; Союз первого результата (AX)
push bx ; Союз второго результата (BX)
mov cx, 3 ; Допустим, вы хотите просто добавить 3
push cx ; Союз третьего результата
; Восстановление регистров
pop cx ; Восстанавливаем CX (последний добавленный)
pop bx ; Восстанавливаем BX
pop ax ; Восстанавливаем AX
pop di ; Восстанавливаем DI
pop si ; Восстанавливаем SI
ret ; Возврат в вызывающий код
Завершение работы программы
После выхода из подпрограммы нужно убедиться, что результаты правильно извлекаются из стека и выводятся на экран. В вашем основном коде всё правильно, но убедитесь, что порядок извлечения соответствует тому, как были помещены значения в стек.
Рекомендуется проводить отладку с помощью отладчика (например, DOSBox с встроенным отладчиком) для отслеживания корректности передачи данных и вызова функций.
Заключение
Для успешной работы с подпрограммами в ассемблере важно обратить внимание на порядок операции с регистром, использование стека и сохранение состояния перед и после выполнения функций. Следуя этим рекомендациям и сделанным исправлениям, вы избежите зацикливания и других проблем с логикой программы.