Не так уж и сложно. Почти так же, как и в языках высокого уровня. Только в ЯВУ этот механизм скрыт от программиста.
Для хранения локальных переменных используется системный стек. Если для передаваемых параметров не хватает регистров, то их тоже передают через стек.
Пример рекурсивной функции с реализацией модели вызова stdcall в TASM для 16-разрядного режима:
recursive proc
;Локальные переменные с символическими метками
local1 equ [ bp-2 ];локальная переменная №1
local2 equ [ bp-4 ];локальная переменная №2
;Символические метки на передаваемые параметры (передаются, как const)
const1 equ [ bp+6 ];переменная №1
const2 equ [ bp+4 ];переменная №2
;формирование фрейма стека для хранения локальных переменных
push bp
mov bp,sp
sub sp,4
...
mov local1,ax;Запись в локальную переменную №1
add ax,const2;Использование входной переменной №2
mov dx,const1;Загрузка входной переменной №1
push ax;Передача переменной №1 для рекурсии
push dx;Передача переменной №2 для рекурсии
call recursive
mov local2,ax;сохранение возвращённого результата в лок. переменную №2
...
mov ax,local2
sub ax,local1;В ах результат выполнения функции
mov sp,bp;Уничтожение фрейма стека (локальных переменных)
pop bp
ret 4;Возврат с уничтожением переданных параметров (восстановление стека согласно stdcall)
;Вызов рекурсивной функции из тела основной программы
mov bx,1234h
push bx; загрузка первой переменной
mov si,56ABh
push si; загрузка второй переменной
call recursive;Вызов рекурсии. Результат вернётся в ax
Для 32-разрядного режима всё так же с учётом разрядности:
recursive proc
;Локальные переменные с символическими метками
local1 equ [ ebp-4 ];локальная переменная №1
local2 equ [ ebp-8 ];локальная переменная №2
;Символические метки на передаваемые параметры (передаются, как const)
const1 equ [ ebp+12 ];переменная №1
const2 equ [ ebp+8 ];переменная №2
;формирование фрейма стека для хранения локальных переменных
push ebp
mov ebp,esp
sub esp,8
...
mov local1,eax;Запись в локальную переменную №1
add eax,const2;Использование входной переменной №2
mov edx,const1;Загрузка входной переменной №1
push eax;Передача переменной №1 для рекурсии
push edx;Передача переменной №2 для рекурсии
call recursive
mov local2,eax;сохранение возвращённого результата в лок. переменную №2
...
mov eax,local2
sub eax,local1;В eах результат выполнения функции
mov esp,ebp;Уничтожение фрейма стека (локальных переменных)
pop ebp
ret 8;Возврат с уничтожением переданных параметров (восстановление стека согласно stdcall)
;Вызов рекурсивной функции из тела основной программы
mov ebx,12345670h
push ebx; загрузка первой переменной
mov esi,56AB3C61h
push esi; загрузка второй переменной
call recursive;Вызов рекурсии. Результат вернётся в eax
Другие языки программирования и технологии
Как реализовать рекурсию на языке ассемблера? (intel 80х86, masm, tasm или fasm)
Константин Чекенёв
спасибо, а стек получается отчищается вызванной процедурой? Т.е. вызывающий вообще не парится?
Что то вроде такого. На входе EСX = число, на выходе в EAX - факториал
factorial:
xor eax, eax
inc eax
fact:
cmp ecx, 1
je theend
imul ecx
dec ecx
call fact
theend:
ret
factorial:
xor eax, eax
inc eax
fact:
cmp ecx, 1
je theend
imul ecx
dec ecx
call fact
theend:
ret
Константин Чекенёв
а по stdcall?
ассемблер учил давно, по этому синтаксис помню не очень, но как и в любом другом языке программирования, просто вызывай функцию из функции
Константин Чекенёв
В ассемблере нет поддержки рекурсии, параметры процедур затираются, ассемблер это не си и даже не фортран и прямой поддержки рекурсии в нём нет, нужно реализовывать ручками.
вот, что-то делал, уже не помню что.
brainFuck proc
arg depth:word
pushbp
movbp,sp
pushsi
pushax
pushbx
pushcx
pushdx
pushdi
movcx,number
salcx,1
xor si,si
cycle:
movdi,si
adddi,depth
incdi
cmpdi,cx
jgeoutofcyc
cmp[mas_number+si],0
jne outofcyc
cmp[mas_number+di],0
jneoutofcyc
movax,depth
mov[mas_number+si],al
mov[mas_number+di],al
cmpax,number
jnep_else
xor si,si
cyc2:moval,[mas_number+si]
mov[finish_number+si],al
incsi
cmpsi,cx
jlcyc2
jmpreturnfrom
p_else:
movbx,depth
incbx
pushbx
callbrainFuck
mov[mas_number+si],0
mov[mas_number+di],0
outofcyc:
incsi
cmpsi,cx
jlcycle
returnfrom:
popdi
popdx
popcx
popbx
popax
popsi
popbp
ret[2]
endp
brainFuck proc
arg depth:word
pushbp
movbp,sp
pushsi
pushax
pushbx
pushcx
pushdx
pushdi
movcx,number
salcx,1
xor si,si
cycle:
movdi,si
adddi,depth
incdi
cmpdi,cx
jgeoutofcyc
cmp[mas_number+si],0
jne outofcyc
cmp[mas_number+di],0
jneoutofcyc
movax,depth
mov[mas_number+si],al
mov[mas_number+di],al
cmpax,number
jnep_else
xor si,si
cyc2:moval,[mas_number+si]
mov[finish_number+si],al
incsi
cmpsi,cx
jlcyc2
jmpreturnfrom
p_else:
movbx,depth
incbx
pushbx
callbrainFuck
mov[mas_number+si],0
mov[mas_number+di],0
outofcyc:
incsi
cmpsi,cx
jlcycle
returnfrom:
popdi
popdx
popcx
popbx
popax
popsi
popbp
ret[2]
endp
Константин Чекенёв
Вооот. Наконец. В дуре 1 параметр word, передаётся через стек да?
Похожие вопросы
- Вопрос по изучению языка Ассемблера под MS DOS. (Нужны советы по программному обеспечению/программированию)
- Сравнение языка Ассемблера и Си
- Почему разновидностей языка ассемблера так много?
- Вопрос про язык ассемблера
- 1.Рекурсия в языке программирования Borland Pascal 7.0. 2.Понятие и виды информации. Ее свойства.
- Помогите с написанием программы на языке Ассемблер, алгоритм знаю, вот только команды самого языка - не очень.
- Как школьнику самостоятельно изучить язык Ассемблера?
- На что способен язык Ассемблер? И есть ли у него какие нибудь ограничение?
- Вопрос из разряда компиляторов. На С++ написан код, генерирующий машинный код из команд на языке ассемблер.
- Скажите программирование на Языке ассемблера сложное? в сровнении с С++ ?