Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2014- СП 3.0 ЛАБЫ ОБЯЗАТ.doc
Скачиваний:
99
Добавлен:
01.03.2016
Размер:
896 Кб
Скачать

Call метка_процедуры

Она выполняется в два микрошага: первый заносит в стек текущее EIP, а второй передает управление на метку-операнд процедуры.

Никаких проблем с учетом дополнительного смещения тут не имеется. Когда команда CALLвыполняется,EIPуже «стоит» на начале следующей за CALLкомандой. А это и есть команда продолжения основной процедуры после возврата из процедуры. Полный порядок.

Раз EIPвозврата заносится в стек, то для возврата из процедуры как нельзя лучше подходит рассмотренная выше командаRET.

На рис.7.3 показана картинка, подобная рис.7.2, но приведенная в полное соответствие с порядком вызова процедур через CALLи возврата из них черезRET.

На рис. 7.3 показан момент времени, когда только-только произошел переход в процедуруи процессор сейчас начнет читать из памяти команду к31.

Под линейным образом памяти (а) снизу изображена область системного стека программы (б). Пусть вас не смущает то, что стек изображен «вертикально», в то время как память (а) показана «горизонтально». Это разные участки одного и того же виртуального адресного пространства программы и, вообще говоря, физически в нем никаких направлений нет, а имеется только одно логическое направление возрастания адресов. Так что не придавайте направлениям на картинках особого значения, мы должны проявлять способность абстрагироваться от них.

Рисунок 7.3- Состояние памяти и стека непосредственно после перехода в процедуру. Указатель стекаESPуказывает на только что занесенное в стек командойCALLзначение 142, это адрес возврата на продолжение основной программы.

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

Когда происходит выполнение процедуры, есть полная свобода использовать стек – в него можно сколько угодно раз заносить данные и извлекать их из стека. Условие корректного возврата – нужно, чтобы при выполнении RETрегистр-указательESPимел значение 048, то есть указывал бы на ячейку стека с адресом 142.

Этого можно добиться по-разному. Например, контролировать число команд PUSH и POPв процедуре. Если их поровну, то условиеESP=048 будет выполнено. Но такой прием применим лишь для простых процедур. Для сложных процедур это, если честно, не всегда выполнимо. Поэтому применяют другой способ – запомнить адрес адреса возврата (это не тавтология; то есть адрес 048, по которому записан адрес 142) в специально имеющемся для таких целей регистреEBP(ExtendedBasePointer), называемом «указатель базы». Это решение более правильное и применимое всегда.

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

Mov EBP, ESP ; запоминаем адрес адреса возврата

После этого можно «гулять» по стеку куда угодно и сколько угодно. Но перед выполнением RETнужно выполнить команду-эпилог

Mov ESP, EBP ; восстанавливаем адрес адреса возврата.

И возврат на команду к5 произойдет точно.

Запишем всё это уже текстом псевдокода. Картинок нарисовано достаточно, и вы уже, надеемся, разобрались в сказанном.

Итак, вызов процедуры с прологом и эпилогом:

; основная программа.

. . .

К1

К2

К3

К4

Call P55

K5

. . .

; Код процедуры Р55

P55 proc ; заголовок процедуры играет роль метки входа в неё

Mov EBP, ESP ; пролог - запоминаем адрес адреса возврата

К31

К32

К33

К34

Mov ESP, EBP ;эпилог-восстанавливаем адрес адреса возврата.

RET

P55 endp ; завершитель описания процедуры

. . .