Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка Программир на ассемблере.doc
Скачиваний:
8
Добавлен:
17.09.2019
Размер:
605.7 Кб
Скачать

2.2. Команды ассемблера

В общем случае значения помещаются в регистры с помощью команды MOV. Команда MOV AX,BX пересылает содержимое регистра BX в AX, затирая ранее содержащееся в AX значение. Команда MOV AH,BL приводит к пересылке байта из регистра BL в регистр AH, но MOV AX, BL - недопустимая команда, так как в регистре AX содержится слово, в регистре BL - байт, а длина данных должна иметь одинаковый размер. Команда MOV может также передавать значения из памяти, например,

MOV AX, ACCT_NUMBER

Здесь ACCT_NUMBER - имя переменной, которую создал программист, как в языке высокого уровня. Переменная создается оператором вида

ACCT_NUMBER DW 0

Этот оператор оставляет место для слова (двух байтов), присваивая им значение 0. Другие допустимые символы в этом операторе это DD - для двойного слова и DB - для байта или строк. Ассемблер следит за адресами переменных, поэтому при ассемблировании оператора

MOV AX, ACCT_NUMBER

имя переменной заменяется ее адресом.

Работа с именами переменных - самый простой способ идентификации данных в программах на языке ассемблера. Но имеются различные способы адресации, которые позволяют программе хранить массивы или использовать указатели. Например,

MOV AX, [BX+SI]

пересылает в AX значение, которое содержится по смещению, равному сумме значений регистров BX и SI.

Процессор 8086 является процессором с сегментной организацией памяти. Он позволяет адресовать 1 Мбайт памяти. Так как все регистры - указатели процессора 8086 (BX, SP, BP, SI, DI и IP) имеют 16 бит, то прямой доступ имеют только 64 Кбайта памяти. Эти 64 Кбайта памяти называются сегментом. Для того чтобы адресовать 1 Мбайт памяти, требуется 20-битовый адрес. Поэтому для представления 20-битового адреса используется два регистра (32 бита). Один регистр содержит адрес сегмента, который задается одним из сегментных регистров (CS, DS, SS или ES). Второй регистр является смещением в сегменте.

Процессор использует четыре сегмента: кода, данных, стека и дополнительный. Сегмент кода содержит код программы, сегмент данных - данные программы, сегмент стека - стек программы, а дополнительный сегмент является дополнительной рабочей памятью программы. Полный 20-битовый адрес, адресующий все адресное пространство процессора, вычисляется следующим образом: значение сегментного регистра сдвигается влево на четыре бита (на одну шестнадцатеричную цифру) и к полученному значению прибавляется смещение. Например, если сегментный регистр содержит значение10FA, а смещение равно 1C2, то физический адрес памяти получается по следующей схеме:

Сегментный регистр: 0001 0000 1111 1010 = 10FA

Сегментный регистр

после сдвига: 0001 0000 1111 1010 0000 = 10FA0

Смещение: 0000 0001 1100 0010 = 01C2

Физический адрес: 0001 0001 0001 0110 0010 = 11162

Как видно из примера, начальный адрес сегмента всегда является 20-битовым числом, а так как сегментный регистр имеет только 16 бит, не достающие младшие 4 бита всегда подразумеваются равными нулю. Это означает, что сегменты всегда начинаются на границе параграфа (отрезок памяти в 16 байт называется параграфом).

Адрес памяти представляется в форме “сегмент: смещение”, поэтому рассмотренный в примере адрес задается в виде 10FA:01C2 .

Сегменты могут быть смежными, разделенными, перекрываться полностью или частично. Так как сегменты могут перекрываться, то она и та же ячейка памяти может содержаться во многих сегментах. Это означает, что она может быть адресована более чем одним адресом. Например, следующие адреса указывают на один и тот же байт памяти:

10FA:01C2 10F0:0262 10E0:0362 10A0:0762

Среди ассемблерных команд есть команды загрузки сегментных и относительных адресов переменных.

MOV AX, SEG ACCT_NUMB

помещает значение сегментного регистра, в котором расположен ACCT_NUMB в AX, а впоследствии это значение будет переслано в DS.

MOV BX, OFFSET ACCT_NUMBER

помещает в BX смещение переменной ACCT_NUMBER в сегменте данных. После выполнения этих команд регистры DS:BX будут указывать на ACCT_NUMBER. Если ACCT_NUMBER является одномерным массивом, то для указания на определенный элемент массива может использоваться добавочное смещение. Команда LEA использует другой способ загрузки смещения.

LEA BX, ACCT_NUMBER

Кодовый сегмент содержит последовательность машинных команд, составляющих программу. Например, команда MOV существует в виде нескольких байтов машинного кода, значение байтов которого определяет в какой регистр идет пересылка и откуда. Регистр IP (счетчик команд) содержит величину смещения, которая указывает на ту команду в кодовом сегменте, которая сейчас должна выполняться. После выполнения команды IP увеличивается таким образом, чтобы он указывал на следующую команду. В простейшей программе счетчик команд будет передвигаться от первого байта кодового сегмента к последнему байту, где программа и завершится. Но, как и другие программы, программа на языке ассемблера может быть разбита на процедуры (подпрограммы), поэтому счетчик команд может прыгать из одного места кодового сегмента в другое.

Когда счетчик команд переходит в другое место кодового сегмента, то его старое значение должно быть запомнено, с тем чтобы можно было вернуться в нужное место, так как это делает оператор RETURN в Бейсике, возвращая управление в то место, откуда была вызвана процедура. В ассемблере процедуре присваивается имя, например, COMBINE_DATA, и оператор CALL СOMBINE_DATA передает управление в процедуру. Процедура завершается командой RET (возврат). При вызове процедуры процессор запоминает текущее значение счетчика команд, записывая в стек. Стек - это область, используемая для временного хранения данных. После завершения процедуры старое значение счетчика команд берется из стека и выполнение программы продолжается. Стек также содержится в отдельном сегменте, который, совершенно естественно, называется сегментом стека. Ему соответствует сегментный регистр SS. В регистре SP хранится указатель стека, который всегда указывает на вершину стека и изменяется при засылке в стек и выборке из стека.

На первый взгляд стек кажется достаточно неуклюжим способом хранения информации, но у него есть два преимущества. Во-первых, доступ к его содержимому намного быстрее, чем к переменным, хранящимся в памяти. Во-вторых, стек может использоваться для многих целей. Он может хранить адреса возврата из процедуры, вложенной в другую процедуру. Впоследствии, то же самое пространство может использоваться программистом для хранения данных, которые должны сейчас обрабатываться, но для которых не хватает места в регистрах микропроцессора. Программа выталкивает содержимое регистра в стек командой PUSH, а позднее забирает его оттуда командой POP. Неправильный порядок обмена данными со стеком - источник многочисленных ошибок при программировании на ассемблере.

После того как программист на ассемблере установил три сегментных регистра (CS, DS и SS) и загрузил данные в регистры микропроцессора он имеет широкий набор команд, которые приведены в приложении.

Язык ассемблера обеспечивает несколько вариантов этих команд. Имеется также целый класс команд, называемых псевдооператорами, которые помещаются в текст программы с целью указания ассемблеру как обрабатывать данную программу. Например, один из типов псевдооператоров автоматически вставляет часто используемый кусок кода по всей программе. Такая порция кода называется макросом и именно это свойство ассемблера дало ему название “макроассемблер”.