Как мне поместить результат в стек в подпрограмме?

Вопрос или проблема

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:

В приведенной выше подпрограмме, когда я помещаю свой результат в стек, управление не возвращается к старту, вместо этого запускается бесконечный цикл.

Кстати, вот вопрос, который я пытаюсь решить:

Вам необходимо написать подпрограмму на языке ассемблера, которая:

  1. Принимает 4 входные переменные (которые будут цифрами из вашего номера накат в т.е. 22F-3440, 3440 – это 4 входа).
  2. Возвращает 3 выходные переменные. Эти выходные переменные помещаются (со случайными значениями) перед входными переменными в основной программе.
  3. Создает 5 локальных переменных внутри функции. Инициализированные случайными значениями от 1 до 10.
  4. Использует регистры AX, BX, SI, DI и CX для выполнения операций, но сохраняет и восстанавливает эти регистры до и после использования, чтобы избежать перезаписи их оригинальных значений.
  5. Выходные значения должны быть извлечены в AX, BX и CX после возврата подпрограммы.
  6. Отображает их на консоли.

Ответ или решение

Чтобы решить проблему передачи значений между подпрограммами в ассемблере, важно правильно использовать стек для хранения и передачи данных. В вашем коде есть несколько ключевых моментов, которые необходимо учесть, чтобы избежать зацикливания программы после вызова подпрограммы. Давайте разберём это подробно.

Понимание работы стека

Стек — это структура данных, работающая по принципу "последний пришёл — первый вышел" (LIFO). При вызове подпрограммы (функции) важно, чтобы:

  1. Заранее были размещены все необходимые данные, которые мы собираемся передать в подпрограмму, на стеке.
  2. После завершения выполнения подпрограммы результаты возвращались обратно и корректно извлекались.

Основные шаги для успешной передачи данных в подпрограмму

  1. Сохранение регистров: Ваша подпрограмма должна сохранять важные регистры перед тем, как использовать их, и восстанавливать их после завершения. Это необходимо для предотвращения перезаписи значений, используемых в вызывающем коде.

  2. Передача аргументов: Используйте стек для передачи параметров в подпрограмму. В вашем случае также следует учитывать, что в стеке будут индивидуальные значения, которые подлежат извлечению.

Улучшенный код подпрограммы

Ниже представлен исправленный вариант вашей подпрограммы 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 с встроенным отладчиком) для отслеживания корректности передачи данных и вызова функций.

Заключение

Для успешной работы с подпрограммами в ассемблере важно обратить внимание на порядок операции с регистром, использование стека и сохранение состояния перед и после выполнения функций. Следуя этим рекомендациям и сделанным исправлениям, вы избежите зацикливания и других проблем с логикой программы.

Оцените материал
Добавить комментарий

Капча загружается...