Передача аргументов через стек
Передача аргументов через стек при вызове процедур используется наиболее час-
то. Суть этого способа заключается в том, что вызывающая процедура самостоя-
Процедуры в языке ассемблера 335
заносит в стек передаваемые данные, после чего обращается к вызываемой
процедуре. В главе 10 мы рассматривали процессы, происходящие при передаче
управления процедуре и возврате из нее. При этом мы обсуждали содержимое сте-
ка до и после передачи управления процедуре (см. рис. 10.4 и 10.5). Как следует из
этих рисунков, при передаче управления процедуре процессор автоматически за-
писывает на вершину стека два (для процедур типа near) или четыре (для проце-
дур типа far) байта. Вы помните, что эти байты являются адресом возврата в вызы-
вающую программу. Если перед передачей управления процедуре командой CALL
в стек были записаны переданные процедуре данные или указатели на них, то они
окажутся под адресом возврата.
При рассмотрении архитектуры процессора мы выяснили, что стек обслужива-
ется тремя регистрами: SS, SP и Р. Процессор автоматически работает с регистра-
ми SS и SP в предположении, что они всегда указывают на вершину стека. По этой
причине их содержимое изменять не рекомендуется. Для произвольного доступа
к данным в стеке архитектура процессора имеет специальный регистр ЕВР\ВР (Base
Point — указатель базы). Так же как и для регистра ESP\SP, обращение к ЕВР\ВР
автоматически предполагает работу с сегментом стека. Перед использованием этого
регистра для доступа к данным стека содержимое стека необходимо правильно
инициализировать, что предполагает формирование в нем адреса, который бы ука-
зывал непосредственно на переданные данные. Для этого в
процедуры ре-
комендуется включить дополнительный фрагмент кода. Он имеет свое название —
пролог процедуры. Типичный фрагмент программы, содержащий вызов процеду-
ры с передачей аргументов через стек, может выглядеть так:
model
<22>
<23>
<24>
<25>
<2б>
<27>
<28>
<29>
<30>
proc_l proc near
;начало пролога
push bp
mov
;конец пролога
mov
mov
[bp+6]
к выходу
;начало эпилога
mov
pop bp
ret
;конец эпилога
proc_l endp
. code
main proc
mov
mov
push arg_l
push
процедура
с п аргументами
;доступ к аргументу arg_n для
;доступ к аргументу
процедуры
из процедуры
sp
значения старого bp
;до входа в процедуру
в вызывающую программу
;запись в стек 1-го аргумента
:запись в стек 2-го аргумента
push arg_n ;запись в стек n-го аргумента
call proc_l
процедуры
;действия по очистке стека после возврата из процедуры
336 Глава
Модульное программирование
<32>
<33> ml:
<34> _exit
<35> main endp
<36> end
Код пролога состоит всего из двух команд. Первая команда push bp сохраняет
содержимое ВР в стеке с тем, чтобы исключить порчу находящегося в нем значе-
ния в вызываемой процедуре. Вторая команда пролога
bp,sp настраивает ВР на
вершину стека. После этого можно не волноваться о том, что содержимое SP пере-
станет быть актуальным, и осуществлять прямой доступ к содержимому стека. Что
обычно и делается. Для доступа к
достаточно сместиться от содержимого
на 4, для
— на 6 и т. д. Но эти смещения подходят только для процедур
типа near. Для процедур
far эти значения необходимо скорректировать еще
на 2, так как при вызове процедуры дальнего типа в стек записывается полный
адрес — содержимое CS и IP. Поэтому для доступа к
в строке 9 команда будет
выглядеть так: mov ax,[bp+6], а для
соответственно, mov ax,[bp+8] и т. д.
Конец процедуры также должен быть оформлен особым
обеспечивая
корректный возврат из процедуры. Фрагмент кода, выполняющего такие действия,
имеет свое название — эпилог процедуры. Код эпилога должен восстановить кон-
текст программы в точке вызова процедуры из вызывающей программы. При этом,
в частности, нужно откорректировать содержимое стека, убрав из него ставшие
ненужными аргументы, передававшиеся в процедуру. Это можно сделать несколь-
кими способами.
Можно использовать последовательность из п команд pop xx. Лучше всего
это делать в вызывающей программе сразу после возврата управления из
процедуры.
Можно откорректировать регистр указателя стека SP на величину 2 • п, напри-
мер, командой add sp,NN, где NN = 2 • п, а п — количество аргументов. Это также
лучше делать после возврата управления вызывающей процедуре.
ii Можно использовать машинную команду RET n в качестве последней исполня-
емой команды в процедуре. Здесь п — количество байтов, на которое нужно уве-
личить содержимое регистра ESP\SP после того, как со стека будут сняты со-
ставляющие адреса возврата. Видно, что этот способ аналогичен предыдущему,
но выполняется процессором автоматически.
В каком виде можно передавать аргументы в процедуру? Ранее упоминалось,
что передаваться могут либо данные, либо их адреса (указатели на данные). В язы-
ке высокого уровня это называется передачей по значению и по адресу, соответ-
ственно.
Наиболее простой способ передачи аргументов в процедуру — передача по зна-
чению. Этот способ предполагает, что передаются сами данные, то есть их значе-
ния. Вызываемая программа получает значение аргумента через регистр или через
стек. Естественно, что при передаче переменных через регистр или стек на их раз-
мер накладываются ограничения, связанные с размерностью используемых регис-
тров или стека. Другой важный момент заключается в том,
при передаче аргу-
ментов по значению в вызываемой процедуре обрабатываются их копии. Поэтому
значения переменных в вызывающей процедуре не изменяются.
Процедуры в языке ассемблера 337
Способ передачи аргументов по адресу предполагает, что вызываемая процеду-
ра получает не сами данные, а их адреса. В процедуре нужно извлечь эти адреса
тем же методом, как это делалось для данных, и загрузить их в соответствующие
регистры. После этого, используя адреса в регистрах,
выполнить необхо-
димые операции над самими данными. В отличие от передачи данных по значе-
нию, при передаче данных по адресу в вызываемой процедуре обрабатывается не
копия, а оригинал передаваемых данных. Поэтому при изменении данных в вызы-
ваемой процедуре они автоматически изменяются и в вызывающей программе, так
как изменения касаются одной области памяти.
36>35>34>33>32>30>29>28>27>25>24>23>22> Do'stlaringiz bilan baham: |