Главная
Обратная связь
Дисциплины:
|
Передача параметров в подпрограмму
При вызове подпрограммы необходимо решить вопрос о передачи параметров вызываемой функции. Передача параметров может осуществляться через регистры процессора. Это самый простой способ. Однако, он имеет ряд существенных недостатков:
· при таком способе передачи необходимо повсеместно отслеживать содержимое регистров до и после вызова подпрограммы;
· число переданных параметров ограничивается числом регистров общего назначения, которых, как правило, не хватает.
В связи с этим часто параметры в вызываемую процедуру передаются через стек. В дальнейшем, при передаче параметров будем использовать соглашение, принятое для языка СИ.
На Рис. 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+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. Для того чтобы аргумент помещался в стек в виде одного байта ,необходимо задать значение счетчика в явном виде:
|