Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2 курс / Лекции / Лекция 21 - Процедуры.ppt
Скачиваний:
46
Добавлен:
18.02.2023
Размер:
206.85 Кб
Скачать

Передача параметров через стек

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

Вызываемая процедура читает эти значения из стека.

Для работы со стеком используются три регистра:

ss – сегмент стека,

(e)bp – регистр базы,

(e)sp – текущее смещение в стеке.

Передача параметров через стек

При таком способе передачи код процедуры несколько изменяется:

MyProcPROC

 

 

push

bp

;Настройка базы

mov

bp, sp

 

 

 

pop

bp

;Восстановление базы

ret

 

 

MyProcENDP

 

 

В таком случае: bp – адрес стека на момент передачи управления вызываемой процедуре. По этому адресу располагается старое значение bp.

Пример

.486

model small

Data SEGMENT use16

ASSUME ds:Data

str1

db

'It is first string for test!$'

str2

db

'It is second string!$'

Data ENDS

 

Stk SEGMENT use16 stack

db

256 dup(0)

Stk ENDS

Пример

Code SEGMENT use16

ASSUME cs:Code

StrLen

PROC

push bp

mov

bp, sp

xor

ah,ah

mov

si, [bp+4] ;Чтение адреса строки

next:

 

lodsb

cmp

al,'$'

jz

finprc

inc

ah

jmp

next

finprc:

 

shr

ax, 8

pop

bp

ret

2

StrLen

ENDP

PrintLen PROC

push

bp

mov

bp, sp

mov

cx, 0b800h

mov

es, cx

mov

ax, [bp+4] ;Чтение позиции

mov

cl, 160

mul

cl

mov

di, ax

mov

ax, [bp+6] ;Чтение длины строки

mov

cl, 10

div

cl

mov

cx, ax

mov

ah, 15

add

al, 48

mov

es:[di],ax

mov

al, ch

add

al, 48

mov

es:[di+2], ax

pop

bp

ret

 

PrintLen ENDP

Пример

start:

mov

ax, Data

mov

ds, ax

 

mov

ax, offset str1

push

ax

;Запись в стек адреса строки str1

call

StrLen

 

push

ax

;Запись в стек длины строки str1

push

word ptr 1 ;Запись в стек позиции

call

PrintLen

 

add

sp, 4

 

mov

ax, offset str2

push

ax

;Запись в стек адреса строки str2

call

StrLen

 

push

ax

;Запись в стек длины строки str1

push

word ptr 5 ;Запись в стек позиции

call

PrintLen

 

wait0:

in

al, 60h

cmp

al, 1

 

jnz

wait0

 

mov

ax, 4c00h

 

int

21h

 

Code ENDS end start

Передача параметров через стек

При завершении процедуры необходимо осуществить изъятие переданных параметров из стека. Это можно сделать следующими способами:

используя последовательность команд pop (не рекомендуется);

откорректировать регистр указателя на вершину стека, например с помощью команды add;

используя машинную команду ret n в качестве исполняемой команды в процедуре, где n – количество байт на которое необходимо увеличить содержимое регистра (e)sp.

Возврат значений из процедуры

Возврат значений может осуществляться:

через регистры,

через общую область памяти,

через стек.

При реализации функций на языках программирования высокого уровня возвращаемое значение, если оно приводится к целочисленному значению, передается через регистр EAX или его часть (AL, AX) или регистровую пару EDX:EAX.

Если результат является вещественным значением, то он возвращается через вершину стека сопроцессора.

Возврат результата

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

Возврат через общую область: проблемы те же, что и при передаче значений.

Возврат через стек: также используется регистр (e)bp. Возможны два варианта:

использование для возвращаемых аргументов тех же ячеек в стеке, которые использовались для передачи аргументов в процедуру;

предварительное помещение в стек наряду с передаваемыми аргументами фиктивных аргументов с целью резервирования места для возвращаемого значения.

Локальные переменные

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

Адресация при обращении к локальным переменным осуществляется относительно значения регистра (E)BP в сторону младших адресов.

MyProc

PROC

 

push

bp

 

mov

bp, sp

 

sub

sp, размер_блока_локальных_данных

 

 

 

add

sp, размер_блока_локальных_данных

 

pop

bp

 

ret

 

MyProc

ENDP

 

 

 

Пример

Написать процедуру для вывода сообщения в рамке и протестировать её работу, выведя несколько сообщений. В качестве параметра ей будет передаваться адрес строки в регистре BX. Строка должна заканчиваться символом ‘$’. Для упрощения процедуры можно разбить задачу на подзадачи и написать соответствующие процедуры. Прежде всего нужно вычислить длину строки, чтобы знать ширину рамки. Процедура get_length вычисляет длину строки (адрес передаётся также в BX) и возвращает её в регистре AX.

Для рисования горизонтальной линии из символов предназначена процедура draw_line. В DL передаётся код символа, а в CX — количество символов, которое необходимо вывести на экран. Эта процедура не возвращает никакого значения. Для вывода 2-х символов конца строки написана процедура print_endline. Она вызывается без параметров и тоже не возвращает никакого значения.

use16

;Генерировать 16-битный код

org 100h

;Программа начинается с адреса 100h

jmp start ;Переход на метку start

;----------------------------------------------------------------------

 

 

msg1 db 'Hello!$'

 

 

msg2 db 'asmworld.ru$'

 

msg3 db 'Press any key

...$'

;----------------------------------------------------------------------

 

 

start:

 

 

mov bx,msg1

 

 

call print_message

;Вывод первого сообщения

mov bx,msg2

 

 

call print_message

;Вывод второго сообщения

mov bx,msg3

 

 

call print_message

;Вывод третьего сообщения

mov ah,8

 

;Ввод символа без эха

int 21h

 

 

mov ax,4C00h

 

;\

int 21h

 

;/ Завершение программы

;----------------------------------------------------------------------

 

 

 

 

 

;----------------------------------------------------------------------

;Процедура вывода сообщения в рамке ;В BX передаётся адрес строки

print_message:

 

push ax

;Сохранение регистров

push cx

 

push dx

 

call get_length

;Вызов процедуры вычисления длины строки

mov cx,ax

;Копируем длину строки в CX

mov ah,2

;Функция DOS 02h - вывод символа

mov dl,0xDA

;Левый верхний угол

int 21h

 

mov dl,0xC4

;Горизонтальная линия

call draw_line

;Вызов процедуры рисования линии

mov dl,0xBF

;Правый верхний угол

int 21h

 

call print_endline

;Вызов процедуры вывода конца строки

mov dl,0xB3

;Вертикальная линия

int 21h

 

mov ah,9

;Функция DOS 09h - вывод строки

mov dx,bx ;

Адрес строки в DX

int 21h

 

 

 

mov ah,2

;Функция DOS 02h - вывод символа

mov dl,0xB3

;Вертикальная линия

int 21h

 

call print_endline

;Вызов процедуры вывода конца строки

mov dl,0xC0

;Левый нижний угол

int 21h

 

mov dl,0xC4

;Горизонтальная линия

call draw_line

 

mov dl,0xD9

;Правый нижний угол

int 21h

 

call print_endline

;Вызов процедуры вывода конца строки

pop dx

;Восстановление регистров

pop cx pop ax

ret ;Возврат из процедуры

;Сохранение регистра BX ;Обнуление AX
;Проверка конца строки ;Если конец строки, то выход из процедуры ;Инкремент длины строки ;Инкремент адреса ;Переход к началу цикла
;Восстановление регистра BX ;Возврат из процедуры

;----------------------------------------------------------------------

;Процедура вычисления длины строки (конец строки - символ '$'). ;В BX передаётся адрес строки.

;Возвращает длину строки в регистре AX. get_length:

push bx xor ax,ax

str_loop:

cmp byte[bx],'$' je str_end

inc ax inc bx

jmp str_loop str_end:

pop bx ret