Подпрограммы (процедуры)

 

      Процедуры могут получать или не получать параметры из вызывающей процедуры и могут возвращать или не возвращать результаты. Процедуры, которые что-либо возвращают, называют функциями (Паскаль).

      Различают два основных механизма передачи параметров процедуре:

                - по значению;

                - по ссылке.

      Пусть procedure - имя процедуры, а value - имя некоторой области памяти (переменная). Тогда вызов процедуры с передачей параметра по значению выглядит следующим образом:

      mov  AX, word ptr value      ; процедура получает копию

      call procedure               ; входного параметра

      Вызов с передачей параметра по ссылке будет выглядеть так:

      mov  AX, offset value        ; процедура получает адрес

      call procedure               ; входного или выходного параметра

      Для обмена информацией между вызывающим кодом и процедурой могут использоваться такие каналы:

                - регистры;

                - стек;

                - глобальные переменные;

                - поток кода;

                - блок параметров.

 

      Передача параметров в регистрах

      Если число параметров и сами параметры невелики, лучшим метсом для их передачи являются регистры. Примерами могут служить вызовы функций DOS и BIOS. Языки высокого уровня обычно используют регистр AX (EAX) для размещения результата, который возвращается функцией.

 

      Передача параметров через стек

      Параметры помещаются в стек перед вызовом процедуры. Именно такой метод используют языки высокого уровня (C, Pascal). Для чтения параметров из стека применяют не команду POP, а регистр BP, в который помещают адрес вершины стека после входа в процедуру:

      push  параметр1         ; поместить параметр в стек

      push  параметр2

      call  procedure

      add   SP,  4            ; освободить стек от параметров

      ............

procedure  PROC  near

      push  BP

      mov   BP,  SP

      (команды, которые могут использовать стек)

      mov   AX,  [BP+4]       ; считать параметр2. Его адрес [BP+4], потому что ; при выполнении команды call в стек поместили адрес возврата (2 байта для
; процедуры типа NEAR), а потом еще и BP - 2 байта.

      mov   BX,  [BP+6]       ; считать параметр1.

      (остальные команды)

      pop   BP

      ret

procedure  ENDP

      При использовании стека для передачи параметров процедуры возникает два вопроса: кто должен удалять параметры из стека (процедура или вызывающий код) и в каком порядке помещать параметры в стек. Все возможные варианты ответа на этот вопрос имеют свои "за" и "против". Так, например, если стек освобождает процедура (команда ret число_байтов), то код программы получается меньшим, а если за освобождение стека от параметров отвечает вызывающая функция, то становится возможным последовательными командами CALL вызвать несколько функций с одними и теми же параметрами. Первый способ - более строгий (Pascal), второй - дает больше возможностей для оптимизации (С). Кроме того, в языке С параметры помещают в стек в обратном порядке (справа налево), так что становятся возможными функции с изменяемым числом параметров.

 

      Передача параметров в потоке кода

      Передаваемые данные размещаются прямо в коде программы, сразу после команды call, например (так реализовна процедура print в одной из стандартных библиотек процедур для ассемблера UCRLIB):

      call print

           DB  "This ASCIZ-line will be printed", 0

      (следующая команда)

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

      Лабораторное задание  3_2.

      Передача параметров в потоке кода (так же как и передача параметров в стеке в обратном порядке) позволяет передавать различное число параметров или один параметр различной длины.

 

      Передача параметров в блоке параметров

      Блок параметров - участок памяти, содержащий параметры и располагающийся обычно в сегменте данных. Процедура получает адрес начала такого блока. Таким методом реализованы многие функции DOS и BIOS (поиск файла - использует блок параметров DTA, загрузка и исполнение программы - используется блок параметров EPB).

      Локальные переменные

      Наиболее распространенный способ хранения локальных переменных - стек. Принято распологать локальные переменные сразу после сохраненного значения регистра BP, так что на них можно ссылаться как [BP-2], [BP-4], [BP-6] и т.д.

      Рассмотрим процедуру examp, в которой используются параметры x, y, z и локальные переменные a, b, c (все эти величины предполагаются 2-х байтовыми):

                examp     proc   near

                x             equ         [BP+8]                   ; параметры процедуры

                y             equ         [BP+6]

                z              equ         [BP+4]

                a          equ            [BP- 2]                   ; локальные переменные

                b          equ            [BP- 4]

                c          equ             [BP- 6]

                               push       BP                          ; сохранить BP

                               mov       BP,  SP   ; установить BP для себя

                               sub         SP,  6                     ; зарезервировать 6 байт для локальных переменных

                               (тело процедуры)

                               mov       SP,  BP   ; выбросить из стека локальные переменные

                               pop         BP                          ; восстановить BP вызвавшей процедуры

                               ret           6                             ; возврат с удалением трех параметров из стека

                examp     endp

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

                                                                              [BP+8]  =   x

                                                                              [BP+6]  =   y

                                                                              [BP+4]  =   z

                                                                              [BP+2]  =   IP

                                                               BP®      [BP+0]  =   BP

                                                                              [BP- 2]  =   a

                                                                              [BP- 4]  =   b

                                                               SP®       [BP- 6]  =   c

                                                                                   ¯

      В связи с тем, что последовательности команд

                               push       BP

                               mov       BP,  SP

                               sub         SP,  6

и

                               mov       SP,  BP

                               pop         BP

используются очень часто при построении процедур, были введены специальные команды ENTER и LEAVE, которые их заменяют. С использованием этих команд процедура examp будет выглядеть следующим образом:

                examp     proc   near

                x             equ         [BP+8]

                y             equ         [BP+6]

                z              equ         [BP+4]

                a          equ            [BP- 2]

                b          equ            [BP- 4]

                c          equ             [BP- 6]

                               enter    6,  0                          ; второй параметр - уровень вложенности процедуры

                               (тело процедуры)

                               leave

                               ret           6

                examp     endp

      Активизационной записью процедуры называется следующая информация, размещаемая в стеке: параметры процедуры, IP (адрес возврата), BP (предыдущее значение).

      Стековый кадр - область стека, отведенная для активизационной записи и локальных переменных процедуры.