Передача параметров в подпрограмму  

Передача параметров в подпрограмму

12345

При вызове подпрограммы необходимо решить вопрос о передачи параметров вызываемой функции. Передача параметров может осуществляться через регистры процессора. Это самый простой способ. Однако, он имеет ряд существенных недостатков:

· при таком способе передачи необходимо повсеместно отслеживать содержимое регистров до и после вызова подпрограммы;

· число переданных параметров ограничивается числом регистров общего назначения, которых, как правило, не хватает.

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

На Рис. 1.7 показан вид стека перед выполнением первой команды процедуры Test, если ее вызов из С++ имел следующий вид:

int i,j;

.

.

.

i=25;

j=4;

Test(i,j,1) ;

SP Адрес возврата
SP+2 25(i)
SP+4 4(j)
SP+6

Рис. 1.7. Вид стека перед началом выполнения процедуры Test.

На следующем рисунке показан вид стека после выполнения следующих строк вызываемой процедуры:

...

push bp

mov bp,sp

...

SP BP при вызове BP
SP+2 Адрес возврата BP+2
SP+4 25(i) BP+4
SP+6 4(j) BP+6
SP+8 BP+8

Рис. 1.8. Вид стека после выполнения PUSH и MOV.

Место для автоматически размещаемых переменных резервируется путем вычитания нужного количества байтов из SP. Например, для автоматического размещения массива из 100 байт в процедуре Test должны использоваться следующие операторы:

...

push bp

mov bp,sp

sub sp,100

...

SP BP-100

...

SP+100 BP при вызове BP
SP+102 Адрес возврата BP+2
SP+104 25(i) BP+4
SP+106 4(j) BP+6
SP+108 BP+8

Рис. 1.9. Состояние стека после размещения 100-байтного массива.

Для адресации автоматически размещаемых переменных используется отрицательное смещение относительно регистра BP. Например,

mov BYTE PTR [bp-100], 0

установит значение первого байта 100-байтного массива в 0.

На рис. 1.10 приведена программа написанная на языке СИ, а на рис. 1.11 десамблируемый код этой программы. При этом следует иметь ввиду, что вызовы функций, написанных на языке СИ, производятся не непосредственно из операционной системы, а из специальной программы - загрузчика(Startup Code). При завершении программы управление передается функции завершения(Exit Code). Эти две функции находятся в модуле COx.OBJ, который включается в исполняемый модуль при компоновке.



int test(int, int);

void main(void)

{

int i,j,k;

i=2;

j=4;

k=test(i,j);

}

int test(int i, int j)

{

int k;

k=i*j;

return k;

}

Рис. 1.10

;_main

push bp

mov bp,sp

sub sp,0006

mov word ptr [bp-02], 0002

mov word ptr [bp-04], 0004

push word ptr [bp-04]

push word ptr [bp-02]

call _test

pop cx

pop cx

mov [bp-06], ax

mov sp, bp

pop bp

ret

;_test

push bp

mov bp, sp

sub sp, 0002

mov ax, [bp+04]

imul word ptr [bp+06]

mov [bp-02], ax

mov sp, bp

pop bp

ret

Рис. 1.11.

Для автоматического размещения переменных используется директива LOCAL, которая проводит распределение в стеке поименованных локальных переменных. Дитектива LOCAL имеет следующий формат:

LOCAL аргумент [,аргумент]... [=идентификатор]

Каждый аргумент имеет следующий синтаксис:

имя [ счетчик 1] [:сложный_тип [:счетчик 2 ]]

Здесь сложный_тип представляет тип данных аргумента. Если тип не задан в явной форме используется тип WORD для 16-битовой модели или DWORD для 32-битовой.

Параметр счетчик2 указывает, сколько элементов такого типа опредедяет данный аргумент. Например, описание аргумента

LOCAL tmp:DWORD:4

означает, что аргумент tmp состоит из четырех двойных слов.

По умолчанию счетчик2 имеет значение 1 для всех типов элементов , кроме типаBYTE .Поскольку операции со стеком не работают с отдельными байтами , то при выборе типа BYTE счетчик2 получает значение 2. Для того чтобы аргумент помещался в стек в виде одного байта ,необходимо задать значение счетчика в явном виде:


4220603436108613.html
4220643830095377.html
    PR.RU™