среда, 27 мая 2009 г.

Стек и подпрограммы

В своем изучении ассемблера, я немного отклонился от линии начертанной великим Питерем Аблем, но я думаю он на меня не обидется :) Еще немного поэкспериментируем со стеком и подпрограммами. Немного практики ни когда не повредит, а потом вернемся к генеральной линии партии... ммм.... вернее Питера.... Абеля....

Итак, наша програ продолжает мутировать:

Оператор CALL вызывает подпрограмму subp, которую мы определили с помощью соответствующих директив PROC и ENDP. Оператор RET осуществляет возврат из подпрограммы в головную программу.
Взглянем на листинг:

Внимательно медитируем на листинг...
Команда call subp имеет машинный код E80005, где собственно E8 – это сама команда, а 0005 – это смещение, указывающее на первую команду нашей подпрограммы. Команда call уменьшает значение SP на два, помещает в стек адрес, следующей за ней команды (в нашем случае адрес команды mov ax,4c00h равный 000F). Затем вычисляет адрес команды подпрограммы, на которую надо передать управление, прибавляя к адресу следующей за ней команды смещение (положительное или отрицательное) равное количеству байт программы, до первой команды вызываемой подпрограммы – в нашем случае 5 байт (000F+5=0014) и помещает это число (в нашем случае 0014) в регистр IP, передавая таким образом управление на подпрограмму. Подпрограмма выполняется до команды RET, которая извлекает из стека адрес возврата из подпрограммы (в нашем случае 000F) и помещает его в регистр IP (передавая, таким образом, управление вызвавшей ее программе) и уменьшает значение SP на два.
И, традиционно, помедитируем на код сгенерированный ассемблером:

Посмотреть на программу в hiew, так же не повредит:

Ну и, святое дело, дебагер:

Скриншот сделан еще до выполнения первой команды. Внимательно медитируем и жмем пять раз F8, то есть останавливаемся на команде call (ее не выполняем).

Из скриншота видно, что отладчик не плохо поорудовал в стеке, но при этом значение регистра SP осталось прежним, и он по прежнему указывает на дно стека (вернее на первое слово под ним). Делаем выводы и далее жмем один раз F7, чтобы войти в подпрограмму.

Как, уже говорилось, команда call уменьшила содержимое регистра SP на два (0040-2=003E), поместила в стек адрес следующей за ней команды (000F), прибавила к адресу следующей за ней команды смещение до первой исполняемой команды подпрограммы (000F+5=14h) и поместила это значение (14h) в регистр IP.
Далее жмем два раза F8.

Команда ret, извлекла из стека адрес возврата из подпрограммы (000F) и поместила его в регистр IP, а затем увеличила значение регистра SP на два, вернув указатель стека, опять на его дно.
Ну и покажем вывод нашей мега программы. Она два раза выводит знаменитую фразочку, но без перевода каретки на новую строку (так как мы это не запрограммировали.

C:\ASM\HELLO\TASM>hello8
-=* Hello World *=--=* Hello World *=-
C:\ASM\HELLO\TASM>

Комментариев нет: