Ближние подпрограммы
Ближние подпрограммы
При входе в ближнюю (near) подпрограмму и при возврате из нее текущее содержимое сегментного регистра cs не изменяется. Это означает, что вызов ближней подпрограммы возможен только из того сегмента, в котором она описана. Все подпрограммы, приведенные в примерах основной части книги и ее приложений, являются ближними, поэтому они могут располагаться только в разделе кодов задачи.
От простой группы команд ближняя подпрограмма отличается только тем, что первая команда обязательно имеет метку (имя), а последней выполняемой командой является ret или retn (это два разных имени одной инструкции). Она (ret) просто выталкивает содержимое верхушки стека в счетчик команд (регистр IP) и увеличивает адрес указателя стека на 2, т. е. равноценна команде pop ip. В результате происходит возврат на вызывающий модуль.
Выражение "последняя выполняемая команда" надо понимать буквально, ret завершает не текст подпрограммы, а ее выполнение. В простых случаях она может завершать текст подпрограммы, но если последняя имеет разветвления, то каждая ветвь может заканчиваться командой ret.
Обращение к подпрограмме (ее вызов) выполняет специальная команда сан, содержащая адрес точки входа. Для его указания можно использовать все стандартные способы адресации, например, имя точки входа, явное задание адреса, выбор адреса из регистра и т. д. Команда call помещает в стек адрес возврата и выполняет безусловный переход на указанную точку входа. Адресом возврата является текущее содержимое счетчика команд (IP). После выборки кода инструкции и операндов IP всегда содержит адрес начала следующей команды. Таким образом, специальная команда call нужна для того, чтобы сформировать в стеке адрес возврата для команды ret, завершающей выполнение подпрограммы.
Подпрограмма может работать, и обычно работает, со стеком. Причем к моменту выполнения команды ret в верхушке стека должен находиться адрес возврата. Сказанное не означает, что его нельзя изменять. Это делается в особых случаях, когда по каким-то причинам надо вернуться не на вызывающий модуль, а в любое другое место задачи.