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

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

void proc56(int par1, int par2){

int x, y;

float *z;

// . . . код процедуры

}

Переменные x,y,zсоздаются в памяти в момент вызова процедурыproc56, живут, пока она выполняется, затем уничтожаются.

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

Внутренние переменные также размещаются в стеке. Для их размещения резервируются ячейки стека, размещенные ниже базы. Сколько переменных – столько ячеек стека, как правило, по 4 байта.

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

Sub ESP, 12 ; это ESP = ESP – 12;

и резервирование выполнено.

Рассмотрим пример. Предположим, описана процедура

Proc56 PROC num1:DWORD, num2:DWORD

; нужны три внутренних переменных x:DWORD, y:DWORD, z:DWORD

PUSH EBP ; пролог

MOV EBP, ESP

SUB ESP, 12 ; резервирование места под x, y, z

;--------------- Момент А. ----------------

; код процедуры

; . . .

MOV ESB, EBP ; эпилог

POP EBP

RET 8 ; очистить 8 байт стека (параметры) при возврате

Proc56 ENDP

Если изобразить состояние стека в момент А после вызова этой процедуры, то получится картинка как на рис. 7.6.

Рисунок 7.6– Стековый кадр процедурыProc56 в момент А. Видны поля трех внутренних переменныхx,y,z, каждая размером 4 байта (DWORD).

Символическими именами внутренних переменных при исполнении Proc56 будут:

  • для x – [EBP-4];

  • для у - [EBP-8];

  • для z-[EBP-12].

      1. Как компилятор ml.ExEпомогает организовать работу с процедурами

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

Отсюда вполне понятно стремление разработчиков пакета MASM32 облегчить практическим программистам работу с процедурами. Хотелось бы сделать так, чтобы программист мог сосредоточиться на смысле решаемой процедурой задачи, а техническое оформление вызовов-возвратов можно было бы возложить на какого-нибудь программного помощника. В качестве такого помощника наилучшим образом выступает компиляторML.EXE. Расскажем, как он нам помогает с процедурами.

        1. Автоматическое создание пролога и эпилога

Предположим, вы описываете в исходном тексте процедуру (для конкретности, пусть ее имя SpendTime, и у неё два параметра, каждый в двойное слово, т.е. оп 4 байта). Список формальних параметров с указанием их типа (т.е. размера) следует помещать в строку заголовка, а в необходимых местах записать команду RET, безо всяких операндов:

SpendTime PROC W:DWORD, S:DWORD

; . . .

; код процедуры

; . . .

RET

SpendTime ENDP

Макрогенератор превратит ваше описание процедуры в следующее:

0000001B SpendTime PROC W:DWORD, S:DWORD

0000001B 55 * push ebp

0000001C 8B EC * mov ebp, esp

; . . .

; код процедуры

; . . .

0000002C C9 * leave

0000002D C2 0008 * ret 00008h

00000030 SpendTime ENDP

Звездочками отмечены строки, которые в текст вставил макрогенератор. Как видим, по смещениям 1Bи 1С записан пролог. По смещению 2Cдобавлена командаleave, которая в точности делаетMOV ESB, EBP /

POP EBP, но одной командой, а не двумя; это – эпилог. Ну, и у командыretпоявился операнд 8, это очищение стека от восьми байт, в которых сидели дваDWORD-параметра.