Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Тема 6.6 Процедуры. Вызов, возврат и их типы - внутри- и межсегментные.




Тема 6. 6 Процедуры. Вызов, возврат и их типы - внутри- и межсегментные.

 

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

uбывает необходимо скомпоновать программы, написанные на разных языках, например, для объединения мощности языка высокого уровня и эффективности Ассемблера;

uпрограмма, написанная в виде одного модуля, может оказаться слишком большой для ассемблирования;

uотдельные части программы могут быть написаны разными группами программистов, ассемблирующих свои модули раздельно;

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

Каждая программа ассемблируется отдельно и генерирует собственный уникальный объектный (OBJ) модуль. Программа компоновщик (LINK) затем компонует объектные модули в один объединенный выполняемый (EXE) модуль.

Обычно выполнение начинается с основной программы, которая вызывает одну или более подпрограмм. Подпрограммы, в свою очередь, могут вызывать другие подпрограммы.

Существует много разновидностей организации подпрограмм, но любая организация должна быть «понятна» и Ассемблеру, и компоновщику, и этапу выполнения. Следует быть внимательным к ситуациям, когда, например, подпрограмма 1 вызывает подпрограмму 2, которая вызывает подпрограмму 3 и, которая в свою очередь вызывает подпрограмму 1. Такой процесс, известный как рекурсия, может использоваться на практике, но при неаккуратном обращении может вызвать любопытные ошибки при выполнении.

Команды CALL используются для внутрисегментных вызовов, то есть, для вызовов внутри одного сегмента. Внутрисегментный CALL может быть короткий (в пределах от +127 до -128 байт) или длинный (превышающий указанные границы). В результате такой операции «старое» значение в регистре IP запоминается в стеке, а «новый» адрес перехода загружается в этот регистр.

Например, внутрисегментный CALL может иметь следующий объектный код: E82000. Шест. E8 представляет собой код операции, которая заносит 2000 в виде относительного адреса 0020 в регистр IP. Затем процессор объединяет текущий адрес в регистре CS и относительный адрес в регистре IP для получения адреса следующей выполняемой команды. При возврате из процедуры команда RET восстанавливает из стека старое значение в регистре IP и передает управление таким образом на следующую после CALL команду.

 

 

Тема 6. 7 Передача параметров процедуре через стек

 

Перед вызовом процедуры параметры необходимо поместить в стек с помощью команды PUSH. Здесь существует два варианта: параметры могут помещаться в стек в прямом или в обратном порядке. Обычно используется обратный порядок и его я буду использовать в примерах. Параметры помещаются в стек, начиная с последнего, так что перед вызовом процедуры на вершине стека оказывается первый параметр:

; Данные

arg0 dw 0

arg1 dw 12

argN dw 345

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

; Код

push [argN]

push. ..

push [arg1]

push [arg0]

call myproc

Перед выполнением команды CALL стек будет иметь следующий вид:

Обращение к параметрам внутри процедуры

Для обращения к параметрам внутри процедуры обычно используют регистр BP. В самом начале процедуры содержимое регистра BP сохраняется в стеке и в него копируется значение регистра SP. Это позволяет «запомнить» положение вершины стека и адресовать параметры относительно регистра BP.

; Процедура

myproc:

push bp

mov bp, sp

...

При выполнении кода процедуры стек будет иметь следующую структуру:

Здесь

ret_addr

обозначает адрес возврата, помещаемый в стек командой вызова процедуры, а bp — сохранённое значение регистра BP. В нашем случае стек имеет ширину 16 бит, поэтому первый параметр будет доступен как

word[bp+4]

, второй как

word[bp+6]

и так далее.

mov ax, [bp+4]; AX = arg0

mov bx, [bp+6]; BX = arg1

add ax, [bp+8]; AX = AX + arg2

Полезно представлять себе стек, чтобы правильно указывать смещения относительно регистра BP. Не забудьте перед возвратом из процедуры восстановить значение BP из стека.

Извлечение параметров из стека

После того, как процедура выполнилась, необходимо очистить стек, вытолкнув из него параметры. Тут тоже существует 2 способа: стек может быть очищен самой процедурой или кодом, который эту процедуру вызывал. Для первого способа используется команда RET с одним операндом, который должен быть равен количеству байтов, выталкиваемых из стека. В нашем случае он должен быть равен количеству параметров, умноженному на 2.

push [arg1]

push [arg0]

call myproc

...

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

; Процедура c двумя параметрами

myproc:

push bp

mov bp, sp

...

pop bp

ret 4; Из стека дополнительно извлекается 4 байта

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

push [arg1]

push [arg0]

call myproc2

add sp, 4; Восстановление указателя стека

...

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

; Процедура с двумя параметрами (не очищает стек)

myproc2:

push bp

mov bp, sp

...

pop bp

ret

Соглашения вызова

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

 

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...