CodeNet / Языки программирования / Ассемблер / СПРАВОЧНИК по системе программирования ТУРБО АССЕМБЛЕР 2.0
СПРАВОЧНИК по системе программирования ТУРБО АССЕМБЛЕР 2.0
Передача параметров
-----------------------------------------------------------------
Из программ, вызывающих подпрограммы (которые называют вызы-
вающими программами или вызывающим кодом), подпрограммам часто
передается информация. Например, в примере программы предыдущего
раздела для передачи в подпрограмму PrintString использовался ре-
гистр BX. Это действие называется передачей параметров. При этом
параметры указывают подпрограмме, что нужно сделать.
Существует два общепринятых способа передачи параметров: в
регистрах и в стеке. Передача параметров через регистры часто ис-
пользуется в чистом коде Ассемблера, а передача через стек ис-
пользуется в большинстве языков высокого уровня, включая Паскаль
и Си, и в подпрограммах на Ассемблере, вызываемых из этих языков.
Передача параметров в регистрах очень проста. Для этого нуж-
но просто поместить значения-параметры в соответствующие регистры
и вызвать подпрограмму. Каждая подпрограмма может иметь свои
собственные потребности в параметрах, хотя вы вероятно поймете,
что чтобы избежать путаницы, лучше выработать некоторые соглаше-
ния и придерживаться их. Например, вы можете следовать правилу,
согласно которому первый параметр-указатель всегда передается в
регистре BX, второй - в SI и т.д. Если вы используете для переда-
чи параметров регистры, аккуратно комментируйте каждую подпрог-
рамму - какие параметры она получает и в каких регистрах они
должны находиться.
Передача параметров в стеке несколько более сложна и отлича-
ется значительно меньшей гибкостью, чем передача их через регист-
ры. Если вы решили использовать передачу параметров через стек,
вы вероятно будете использовать соглашения, принятые в предпочи-
таемом вами языке высокого уровня. Это позволит легко компоновать
подпрограммы на Ассемблере с программами, написанными на данном
языке. В соответствующих главах и приложениях данного руководства
приводится полное описание соглашений по передаче параметров в
Турбо Си, Турбо Паскале, Турбо Бейсике и Турбо Прологе, и приве-
дены примеры на Ассемблере.
Возвращаемые значения
-----------------------------------------------------------------
Подпрограммы часто возвращают значения в вызывающую програм-
му. В программах на Ассемблере, которые предполагается вызывать
из программы на языке высокого уровня, для возврата значений вы
должны следовать соглашениям данного языка. Например, функции,
вызываемые в языке Си, должны возвращать 8- или 16-битовые значе-
ния (значения символьного, целого типа и ближние указатели) в ре-
гистре AX, а 32-битовые значения (длинные целые и дальние указа-
тели) - в паре регистров DX:AX. В главах 6 - 9 данного руководст-
ва дается подробное описание соглашений по возвращаемым значениям
языка Турбо Си, Турбо Паскаля, Турбо Бейсика и Турбо Пролога.
В программах, где используется только язык Ассемблера, в от-
ношении возвращаемых значений допускается полная свобода: вы по-
жете помещать их в тот регистр, какой захотите. Фактически, в ре-
гистре флагов подпрограммы могут даже возвращать информацию о
состоянии (в виде установки флага переноса или флага нуля). Одна-
ко, лучше установить некоторые соглашения и их придерживаться.
Полезным соглашением может служить возврат 8-битовых значений в
регистре AL и 16-битовых значений в регистре AX.
Основная проблема при использовании в Ассемблере возвращае-
мых подпрограммами значений состоит в том, что при возврате
информации подпрограммы могут разрушить важную для вызывающей
программы информацию. В Ассемблере легче писать обращение к
подпрограмме, не помня о том, что подпрограмма возвращает
значение, скажем в SI (или что данная подпрограмма просто
изменяет SI), но при этом вы получите программу, в которой трудно
будет выявлять ошибки.
По этой причине лучше сводить к минимуму число значений,
возвращаемых в регистрах (лучше всего до одного) и возвращать до-
полнительные значения, сохраняя их в ячейках памяти, на которые
ссылаются передаваемые указатели (как это делается в Паскале и
Си).
Сохранение регистров
-----------------------------------------------------------------
Соответствующее сохранение регистров при обращении к под-
программе - это существенный момент в программировании на Ассем-
блере. В современных языках высокого уровня подпрограмма обычно
не может изменить значения переменных вызывающей программы, если
вызывающая программа этого явным образом не допускает. В Ассем-
блере это не так: переменные вызывающей программы хранятся часто
в тех же регистрах, что и регистры, используемые подпрограммой.
Например, если подпрограмма изменяет регистр, значение которого
вызывающая программа установила перед вызовом подпрограммы, но
который она использует после обращения к ней, вы получите ошибку.
Одно из решений этой проблемы состоит в том, чтобы при входе
в каждую подпрограмму заносить в стек все используемые ей регист-
ры и восстанавливать их из стека перед возвратом в вызывающую
программу. К сожалению, для этого требуется существенное время и
большой объем кода. Другая возможность заключается в том, чтобы
ввести правило, что вызывающая программа никогда не рассчитывает
на сохранение регистров подпрограммой и все функции по их сохра-
нению выполняет сама. Но это малопривлекательно, поскольку су-
щественным доводом в пользу применения Ассемблера является свобо-
да эффективного использования регистров.
Если говорить кратко, то в языке Ассемблера существует ко-
нфликт между скоростью и простотой программирования. Если вы со-
бираетесь использовать Ассемблер, вы сможете писать быстрые и
компактные программы, а это означает, что нужно разумно относить-
ся к сохранению регистров и обеспечить, чтобы при вызове каждой
подпрограммы из-за регистров не возникало конфликтов. Наилучшим
подходом является аккуратное комментирование каждой подпрограммы
и указание, какие регистры она использует, и обращение к данным
комментариями при каждом вызове подпрограммы.
Нужно уделять внимание как отслеживанию сохранения регист-
ров, так и максимально эффективному их использованию. В програм-
мировании на Ассемблере это одинаково важно. Языки высокого уров-
ня выполняют за вас эту работу, но они, как мы уже упоминали, не
позволяют получать такие быстрые и компактные программы, какие
можно получить с помощью Ассемблера.
