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