1) in аккумулятор, номер_порта – ввод в аккумулятор из порта с номером номер_порта;
2) out порт, аккумулятор – вывод содержимого аккумулятора в порт с номером номер_порта.
Команды работы с адресами и указателями памятиПри написании программ на ассемблере производится интенсивная работа с адресами операндов, находящимися в памяти. Для поддержки такого рода операций есть специальная группа команд, в которую входят следующие команды:
1) lea назначение, источник – загрузка эффективного адреса;
2) Ids назначение, источник – загрузка указателя в регистр сегмента данных ds;
3) les назначение, источник – загрузка указателя в регистр дополнительного сегмента данных es;
4) lgs назначение, источник – загрузка указателя в регистр дополнительного сегмента данных gs;
5) lfs назначение, источник – загрузка указателя в регистр дополнительного сегмента данных fs;
6) lss назначение, источник – загрузка указателя в регистр сегмента стека ss.
Команда lea похожа на команду mov тем, что она также производит пересылку. Однако команда lea производит пересылку не данных, а эффективного адреса данных (т. е. смещения данных относительно начала сегмента данных) в регистр, указанный операндом назначение.
Часто для выполнения некоторых действий в программе недостаточно знать значение одного лишь эффективного адреса данных, а необходимо иметь полный указатель на данные. Полный указатель на данные состоит из сегментной составляющей и смещения. Все остальные команды этой группы позволяют получить в паре регистров такой полный указатель на операнд в памяти. При этом имя сегментного регистра, в который помещается сегментная составляющая адреса, определяется кодом операции. Соответственно смещение помещается в регистр общего назначения, указанный операндом назначение.
Но не все так просто с операндом источник. На самом деле, в команде в качестве источника нельзя указывать непосредственно имя операнда в памяти, на который мы бы хотели получить указатель. Предварительно необходимо получить само значение полного указателя в некоторой области памяти и указать в команде получения полный адрес имени этой области. Для выполнения этого действия необходимо вспомнить директивы резервирования и инициализации памяти.
При применении этих директив возможен частный случай, когда в поле операндов указывается имя другой директивы определения данных (фактически, имя переменной). В этом случае в памяти формируется адрес этой переменной. Какой адрес будет сформирован (эффективный или полный), зависит от применяемой директивы. Если это dw, то в памяти формируется только 16-битное значение эффективного адреса, если же dd – в память записывается полный адрес. Размещение этого адреса в памяти следующее: в младшем слове находится смещение, в старшем – 16-битная сегментная составляющая адреса.
Например, при организации работы с цепочкой символов удобно поместить ее начальный адрес в некоторый регистр и далее в цикле модифицировать это значение для последовательного доступа к элементам цепочки.
Необходимость использования команд получения полного указателя данных в памяти, т. е. адреса сегмента и значения смещения внутри сегмента, возникает, в частности, при работе с цепочками.
Команды преобразования данныхК этой группе можно отнести множество команд микропроцессора, но большинство из них имеет те или иные особенности, которые требуют отнести их к другим функциональным группам. Поэтому из всей совокупности команд микропроцессора непосредственно к командам преобразования данных можно отнести только одну команду: xlat [адрес_таблицы_перекодировки]
Это очень интересная и полезная команда. Ее действие заключается в том, что она замещает значение в регистре al другим байтом из таблицы в памяти, расположенной по адресу, указанному операндом адрес_таблицы_перекодировки.
Слово «таблица» весьма условно, по сути, это просто строка байт. Адрес байта в строке, которым будет производиться замещение содержимого регистра al, определяется суммой (bx) + (al), т. е. содержимое al исполняет роль индекса в байтовом массиве.
При работе с командой xlat обратите внимание на следующий тонкий момент. Несмотря на то что в команде указывается адрес строки байт, из которой должно быть извлечено новое значение, этот адрес должен быть предварительно загружен (например, с помощью команды lea) в регистр bх. Таким образом, операнд адрес_таблицы_перекодировки на самом деле не нужен (необязательность операнда показана заключением его в квадратные скобки). Что касается строки байт (таблицы перекодировки), то она представляет собой область памяти размером от 1 до 255 байт (диапазон числа без знака в 8-битном регистре).
Команды работы со стекомЭта группа представляет собой набор специализированных команд, ориентированных на организацию гибкой и эффективной работы со стеком.
Стек – это область памяти, специально выделяемая для временного хранения данных программы. Важность стека определяется тем, что для него в структуре программы предусмотрен отдельный сегмент. На тот случай, если программист забыл описать сегмент стека в своей программе, компоновщик tlink выдаст предупреждающее сообщение.
Для работы со стеком предназначены три регистра:
1) ss – сегментный регистр стека;
2) sp/esp – регистр указателя стека;
3) bp/ebp – регистр указателя базы кадра стека.
Размер стека зависит от режима работы микропроцессора и ограничивается 64 Кбайтами (или 4 Гбайтами в защищенном режиме).
В каждый момент времени доступен только один стек, адрес сегмента которого содержится в регистре SS. Этот стек называется текущим. Для того чтобы обратиться к другому стеку («переключить стек»), необходимо загрузить в регистр ss другой адрес. Регистр SS автоматически используется процессором для выполнения всех команд, работающих со стеком.
Перечислим еще некоторые особенности работы со стеком:
1) запись и чтение данных в стеке осуществляется в соответствии с принципом LIFO,
2) по мере записи данных в стек последний растет в сторону младших адресов. Эта особенность заложена в алгоритм команд работы со стеком;
3) при использовании регистров esp/sp и ebp/bp для адресации памяти ассемблер автоматически считает, что содержащиеся в нем значения представляют собой смещения относительно сегментного регистра ss.
В общем случае стек организован так, как показано на рисунке 23.
Рис. 23. Концептуальная схема организации стека
Для работы со стеком предназначены регистры SS, ESP/SP и ЕВР/ВР. Эти регистры используются комплексно, и каждый из них имеет свое функциональное назначение.
Регистр ESP/SP всегда указывает на вершину стека, т. е. содержит смещение, по которому в стек был занесен последний элемент. Команды работы со стеком неявно изменяют этот регистр так, чтобы он указывал всегда на последний записанный в стек элемент. Если стек пуст, то значение esp равно адресу последнего байта сегмента, выделенного под стек. При занесении элемента в стек процессор уменьшает значение регистра esp, а затем записывает элемент по адресу новой вершины. При извлечении данных из стека процессор копирует элемент, расположенный по адресу вершины, а затем увеличивает значение регистра указателя стека esp. Таким образом, получается, что стек растет вниз, в сторону уменьшения адресов.
Что делать, если нам необходимо получить доступ к элементам не на вершине, а внутри стека? Для этого применяют регистр ЕВР Регистр ЕВР – регистр указателя базы кадра стека.
Например, типичным приемом при входе в подпрограмму является передача нужных параметров путем записи их в стек. Если подпрограмма тоже активно работает со стеком, то доступ к этим параметрам становится проблематичным. Выход в том, чтобы после записи нужных данных в стек сохранить адрес вершины стека в указателе кадра (базы) стека – регистре ЕВР. Значение в ЕВР в дальнейшем можно использовать для доступа к переданным параметрам.
Начало стека расположено в старших адресах памяти. На рисунке 23 этот адрес обозначен парой ss: fffF. Смещение шТ приведено здесь условно. Реально это значение определяется величиной, которую программист задает при описании сегмента стека в своей программе.
Для организации работы со стеком существуют специальные команды записи и чтения.
1. push источник – запись значения источник в вершину стека.
Интерес представляет алгоритм работы этой команды, который включает следующие действия (рис. 24):
1) (sp) = (sp) – 2; значение sp уменьшается на 2;
2) значение из источника записывается по адресу, указываемому парой ss: sp.
Рис. 24. Принцип работы команды push