Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
flor_apparato-orientirovnnoe_prog.doc
Скачиваний:
89
Добавлен:
15.06.2014
Размер:
926.72 Кб
Скачать

4. Использование неэлементарных способов адресации

4.1. Косвенно-регистровая адресация

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

Действительно, для доступа к памяти мы использовали до сих пор только прямую адресацию. Она позволяет указывать в качестве операнда фиксированное место в памяти. Для этого мы задавали в качестве операнда ограниченное квадратными скобками имя области памяти, либо, в качестве ассемблерных расширений исходной возможности записывали имя области с прибавлением к нему в записи операнда фиксированной числовой величины. На самом деле за этими записями на ассемблере стояли внутренние в машинных кодах числовые указания, которые на ассемблере можно записать в виде [числовое смещение].

Таких средств явно недостаточно для полноценного программирования. Поэтому с самого начала компьютерной эры в архитектуре процессоров используется хотя бы еще один способ адресации, называемый косвенно-регистровой адресацией. Существо этого способа в том, что регистр, заданный для доступа к значению операнда, содержит не само значение операнда, а его адрес (фактически смещение относительно начала сегмента, называемое также относительным адресом).

С получением адреса именованной области данных мы уже встречались при изучении средств обращения к системным функциям. Именно, запись на NASM команды

MOV регистр, имя_области_данных

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

Косвенно-регистровый способ адресации задается на ассемблере записью операнда в виде [имя_регистра]. В качестве регистра, используемого в такой записи, можно применять любые из регистров EAX, EBX, ECX, EDX, ESI, EDI. Для более специальных целей в косвенно-регистровом способе адресации можно применять и регистры ESP, EBP, но делать это вне узкой области специализированного применения не рекомендуется. (Следует заметить, что в 16-битной архитектуре применение регистров для косвенно-регистровой адресации было существенно ограниченным, нельзя было с этой целью использовать регистры AX, CX и DX. Приходилось практически ограничиваться лишь регистрами BX, SI и DI, что было очень неудобно.)

Рассмотрим, как косвенно-регистровый способ адресации применить для доступа к элементам массива. Пусть имеется (для простоты) массив из байтов, описанный с именем tabla и мы хотим в цикле перебирать все его элементы для какого-то анализа или вычислений. Это можно сделать следующим фрагментом программы:

MOV ecx, число_элементов_в_массиве

MOV edx, tabla

povt: mov al, [edx]

анализ или обработка очередного байта, находящегося

сейчас в регистре AL

INC edx

LOOP povt

Первая и последняя команды в этом фрагменте вспомогательные для демонстрации возможностей рассматриваемого способа адресации (цикл может быть организован и как-то иначе). Собственно косвенно-регистровый способ адресации использован здесь во втором операнде третьей команды. Именно, в команде пересылки местом источника данных задается байт памяти, адрес которого содержит регистр edx. В первом шаге выполнения цикла в этом регистре содержится адрес начала области tabla, занесенный предыдущей командой, о которой речь уже шла раньше. Поэтому в первом шаге выполнения цикла в регистр AL пересылается значение первого байта из области tabla. Перед концом цикла использована команда инкремента регистра edx, благодаря которой перед вторым шагом значение адреса в регистре edx увеличивается на единицу, показывая теперь на следующий байт этой области. Эти же действия выполняются в цикле многократно. После доступа к некоторому байты внутри области tabla (пересылке его в регистр AL для обработки и выполнения такой обработки) команда инкремента увеличивает значение адреса в регистре edx, заставляя его в дальнейшем указывать на следующий очередной байт.

Заметим, что нет крайней необходимости увеличивать адрес в регистре, служащей для косвенно-регистровой адресации обязательно на единицу. Можно уменьшать это значение в регистре, обеспечивая перемещение доступа к элементам области от более дальних элементов к более близких, в частности, просмотр массива от последнего элемента к начальному. Можно перескакивать через элемент или через любое число элементов.

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

Новое решение этой проблемы, основанное на косвенно-регистровой адресации приведено далее в листинге 4.1.1.

. . . получение цифр результата и запоминание их в стеке как и ранее

mov [cnt], ecx

mov ebx, numtxt

izv: pop edx

mov byte [ebx],dl ; digit into array for text value

inc ebx

loop izv

mov eax,4 ; N function=write

mov ebx,1 ; N handle=1 (stdout)

mov ecx, numtxt ; address of text

mov edx,[cnt] ; number of byte

int 80h

mov eax, 1 ; N function = exit

int 80h ;

SEGMENT .data

cnt dd 0

SEGMENT .bss

numtxt resb 10

Листинг 4.1.1. Фрагмент вывода цифр результата в Linux

Здесь вместо однобайтовой области digit для единственного выводимого символа цифры сразу заведено десять байтов области numtxt, в которых должны разместиться все цифры числа. Адрес этой области заносится в регистр edx второй командой фрагмента. Далее в цикле после извлечения очередной цифры из стека и при наличии ее после этого в регистре DL выполняется команда пересылки mov byte [ebx],dl. Эта команда переносит содержимое регистра DL (очередную цифру) в байт области numtxt, заданный косвенно-регистровой адресацией через регистр edx. Далее тут же командой инкремента увеличивается значение адреса в регистре edx, заставляя его указывать для следующего шага на дальнейший байт служебной области numtxt. Пока из стека не извлечены все символы цифр, цикл повторяется командой LOOP, число выполнения которой обусловлено начальным значением регистра ecx, где находится число запомненных в стеке цифр. Лишь по завершении этого цикла задается обращение к системной функции вывода, причем адрес области вывода и число символов в ней формируется командами

mov ecx, numtxt

mov edx,[cnt]

которые задают в качестве такой области numtxt и число символов, запомненное ранее в переменной cnt.

Соседние файлы в предмете Системное программное обеспечение