Способ 3, самый частый. ЧЕРЕЗ СТЕК


ИДЕЯ:

1. ПЕРЕД ВЫЗОВОМ
занести параметры в стек;

2. Вызвать процедуру;

3. Запомнить место в стеке через регистр BP (Base Pointer);

4. Внутри процедуры использовать параметры,
адресуясь ОТНОСИТЕЛЬНО BP;

5. Перед выходом восстановить
старое BP;

6. Выйти из процедуры

7. Очистить стек.

 

ОГРАНИЧЕНИЕ: Заносить в стек (PUSH) и читать из него (POP)

можно ТОЛЬКО МАШИННЫЕ СЛОВА (по 2 байта каждое).

 

ВОЗВРАТ ЗНАЧЕНИЙ ЧЕРЕЗ СТЕК

 

Это состояние стека сразу после возврата из процедуры. ГДЕ ТУТ МОЖЕТ БЫТЬ МЕСТО ДЛЯ ЧИСЛА, КОТОРОЕ ПРОЦЕДУРА ОСТАВИЛА В СТЕКЕ ДЛЯ ВЫЗЫВАЮЩЕЙ ПРОГРАММЫ?

 

 

ПРОЦЕДУРА обращается к этому полю как [BP + 8]

ВЫЗЫВАЮЩАЯ ПРОГРАММА обращается к этому полю по адресу SS:SP То есть может прочесть его POP reg / mem

 

ПОРЯДОК ЗАНЕСЕНИЯ ПАРАМЕТРОВ В СТЕК

Procedure AnyProc(x:integer; y:word; z: Pstring);

Begin … … … end;

Чем отличается А от Б?

X ßà [BP+4] или X ßà [BP+8] ?

Компилятор должен ЗАРАНЕЕ знать порядок передачи параметров!

 

КТО ЧИСТИТ СТЕК?

Вариант 1й чистки стека. Это случай, когда стек чистит САМА ВЫЗВАННАЯ ПРОЦЕДУРА.

.model small .stack 100h .data ; пусто. Данные программе не нужны. .code eingang: ;mov ax, @data ; здесь это ;mov ds, ax ; даже не нужно... mov dl, 'f' ; готовим параметр mov dh,0 ; для передачи ч-з стек SUB SP, 2; занять в стеке место ; под возвращаемое. push DX ; занесли параметр в стек call UPCASE ; 'F' <- 'f', результат в стеке pop DX ; забираем из стека результат. mov ah, 2 ; символ уже в DL! int 21h ; выводим его на экран mov ah,8 int 21h ; Press any key... mov ah, 4ch int 21h ; см следующую колонку ;===Процедура - "функция" ======= UPCASE proc push BP ; пролог mov BP, SP mov ax, [BP+4] ; читаем параметр sub AL, ‘f'-'F' ; преобр в верхн регистр mov [BP+6], AX ; запись в стек ; возвращаемого pop BP ; эпилог ret 2 ; выход и чистка стека ; от одного слова (2 байта) endp ;============================= end eingang  

 

Вариант чистки стека №2. стек чистит ВЫЗВАЮЩАЯ ПРОЦЕДУРА.

.model small .stack 100h .data ; пусто. Данные программе не нужны. .code eingang: ;mov ax, @data ; здесь это ;mov ds, ax ; даже не нужно... mov dl, 'f' ; готовим параметр mov dh,0 ; для передачи ч-з стек SUB SP, 2; занять в стеке место ; под возвращаемое. push DX ; занесли параметр в стек call UPCASE ; 'F' <- 'f', результат в стеке ADD SP, 2 ; чистка стека от ; одного параметра (2 байта). pop DX ; забираем из стека результат. mov ah, 2 ; символ уже в DL! int 21h ; выводим его на экран mov ah,8 int 21h ; Press any key... mov ah, 4ch int 21h ; см следующую колонку ;===Процедура - "функция" ======= UPCASE proc push BP ; пролог mov BP, SP mov ax, [BP+4] ; читаем параметр sub AL, ‘f'-'F' ; преобр в верхн регистр mov [BP+6], AX ; запись в стек ; возвращаемого pop BP ; эпилог ret ; выход endp ;============================= end eingang

 

ПАРАМЕТР «ЯЗЫК» ДЛЯ ВЫЗОВА ПРОЦЕДУР

.MODEL SMALL, «язык»

Значение параметра «ЯЗЫК» ПРОСМОТР СПИСКА ПАРАМЕТРОВ КТО ЧИСТИТ СТЕК
C (C++) ß СПРАВА НАЛЕВО Кто ВЫЗВАЛ
PASCAL СЛЕВА НАПРАВО à Процедура
STDCALL ß СПРАВА НАЛЕВО Процедура
SYSCALL ß СПРАВА НАЛЕВО Кто ВЫЗВАЛ

 

ЛОКАЛЬНЫЕ ПЕРЕМЕННЫЕ В ПРОЦЕДУРАХ

Это место создается в прологе:

. . .

PUSH BP

MOV BP, SP

SUB SP, 4 ; по 2 байта на переменную,

; SP смещается с «1» на «2»

 

Но тогда ЭПИлог становится такой:

. . .

MOV SP, BP ; SP смещается с «2» на «1»

POP BP

RET