При вызове процедуры необходимо удовлетворить следующие три требования:
— в отличие от команд переходов команда вызова процедуры должна запомнить адрес возврата (адрес следующей команды после команды вызова процедуры CALL) так, чтобы можно было осуществить возврат в нужное место вызывающей программы по команде RET;
—- процедура должна иметь средства взаимодействия или разделения данных с вызывающей се программой (или процедурой), т.е. иметь- возможность получить данные из вызывающей программы для последующей обработки и возможность вернуть результат;
— используемые процедурой регистры процессора необходимо запоминать (сохранять) до изменения их содержимого, а перед выходом из процедуры — восстанавливать.
Первое из приведенных требований удовлетворяется использованием стека для сохранения адреса возврата. Команда CALL не только осуществляет переход по адресу процедуры, но и включает в стек адрес возврата (рис. 4.2). Команда RET извлекает сохраненный командой CALL адрес возврата из стека и делает его новым текущим адресом команды (изменяет логический адрес в регистрах CS:IP). Предполагается, что если процедура обращалась к стеку, указатель стека возвращается в правильное положение перед выполнением команды возврата. Очевидно, при работе с процедурами необходимо внимательно следить за стеком. В противном случае возможны возвраты к бессмысленным — командам, если во время возврата указатель стека SS:SP будет указывать не на сохраненные командой CALL значения CS:IP.
Программа Стек
Процедура PROC
а)SS:SP (во
после вызова)
Рис. 4.2. Сохранение адреса возврата из процедуры в стеке
Режимы адресации, которые кодируются в команде
CALL, такие же, что и для команд безусловного перехода JftViP (см. п. 3.2.2). Вызов может быть прямым или косвенным, внутрисегментным или межсегментным. Внутрисегментный вызов процедуры сохраняет в стеке только часть логического адреса возврата, а именно, смещение следующей команды в текущем сегменте кода. Межсегментный вызов процедуры сохраняет в стеке полный логический адрес возврата. Если команда CALL является внутрисегментным (межсегментным) вызовом, то и команда RET (рис.4.3) должна быть внутрисегментным (межсегментным) возвратом. Это объясняется тем, что внутрисегментный вызов включает1 в стек только содержимое регистра IP, т.е. смещение в текущем сегменте кода следующей команды после команды вызова процедуры, а межсегментный вызов должен включить в стек как содержимое IP, так и содержимое CS (рис. 4.2). Соответственно возврат должен извлечь из стека одно или два слова.
|
RET NEAR (при F = 0 – внутрисегментный)
RET FAR (при F = 1 – межсегментный)
