assembler. Учебник для вузов_Юров В.И_2003 -637с (862834), страница 61
Текст из файла (страница 61)
К примеру, пусть в программе статически определена последовательность данных:mas dw 0 , 1 , 2 , 3 , 4 , 5Пусть эта последовательность чисел трактуется как одномерный массив. Размерность каждого элемента определяется директивой DW, то есть она равна двумбайтам. Чтобы получить доступ к третьему элем 0 ?" v nv^no к адресу м;,спж;; при-272Глава 13. Сложные структуры данныхбавить 6. Нумерация элементов массива в ассемблере начинается с нуля. То естьв нашем случае речь, фактически, идет о 4-м элементе массива — 3, но об этом знает только программист; процессору в данном случае все равно — ему нужен толькоадрес.
В общем случае для получения адреса элемента в массиве необходимо начальный (базовый) адрес массива сложить с произведением индекса (номер элемента минус единица) этого элемента на размер элемента массива:база + (индекс • размер элемента).Архитектура процессора предоставляет довольно удобные программно-аппаратные средства для работы с массивами.
К ним относятся базовые и индексныерегистры, позволяющие реализовать несколько режимов адресации данных. Используя данные режимы адресации, можно организовать эффективную работус массивами в памяти. Вспомним эти режимы.• Индексная адресация со смещением — режим адресации, при котором эффективный адрес формируется из двух компонентов:П постоянный (базовый) компонент формируется указанием прямого адресамассива в виде имени идентификатора, обозначающего начало массива;П переменный (индексный) компонент формируется указанием имени индексного регистра.К примеру,mas dw 0 , 1 , 2 , 3 , 4 , 5mov si ,4;поместить 3-й элемент массива mas в регистр ах:mov ax,mas[si]» Базовая индексная адресация со смещением — режим адресации, при которомэффективный адрес формируется максимум из трех компонентов:D в качестве постоянного (необязательного) компонента может выступатьпрямой адрес массива в виде имени идентификатора, обозначающего начало массива, или непосредственного значения;D переменный (базовый) компонент формируется указанием имени базовогорегистра;Р переменный (индексный) компонент формируется указанием имени индексного регистра.Этот вид адресации удобно использовать при обработке двухмерных массивов.Пример использования этой адресации мы рассмотрим далее при изучении особенностей работы с двухмерными массивами.Напомним, что в качестве базового регистра может использоваться любой извосьми регистров общего назначения.
В качестве индексного регистра также можно использовать любой регистр общего назначения, за исключением ESP/SP.Процессор позволяет масштабировать индекс. Это означает, что если указатьпосле имени индексного регистра символ звездочки (*) с последующей цифрой 2,4 или 8, то содержимое индексного регистра будет умножаться на 2,4 или 8, то естьмасштабироваться. Применение масштабирования облегчает работу с массивами,которые имеют размер элементов, равный 2, 4 или 8 байт, так как процессор самМассивы273производит коррекцию индекса для получения адреса очередного элемента массива. Нам нужно лишь загрузить в индексный регистр значение требуемого индекса(считая от 0).
Кстати сказать, возможность масштабирования появилась в процессорах Intel, начиная с модели i486. По этой причине в рассматриваемом далее примере программы стоит директива .486. Ее назначение, как и ранее использовавшейся директивы .386, — в том, чтобы указать ассемблеру на необходимость учетадополнительных возможностей новых процессоров при формировании машинныхкоманд.В качестве примера масштабирования рассмотрим листинг 13.2, в котором просматривается массив, состоящий из слов, и производится сравнение этих элементов с нулем.
Выводится соответствующее сообщение.Листинг 13.2. Просмотр массива слов с использованием масштабирования;prg 13 2. asm;tlink /v /3 prg 12 2. objMASHMODELsmallSTACK256.data;начало сегмента данных; тексты сообщений:mesldb "не равен 0!$",0ah,0dhraes2 db"равен 0!$ ",0ah,0dhmes3db 0ah ,0dh ,' Элемент $'mas dw 2,7,0,0,1,9,3, 6,0,8 ; исходный массив.code; это обязательно.486main:mov ax,@data;связка ds с сегментом данныхmov ds.ax;обнуление ахxor ax , axprepare:;значение счетчика цикла в схmov ex, 10; индекс в esimov esi ,0compare:; первый элемент массива в dxmov dx.mas [esi *2]уравнение dx с 0cmp dx,0;переход, если равноje equal;не равноnot_equal :; вывод сообщения на экранmov ah,09hlea dx,mes3int 21h; вывод номера элемента массива на экранmov ah,02hmov dx.siadd dl,30hint 21hmov ah,09hlea dx.meslint 21hна следующий элементinc esiусловие для выхода из циклаdec exсх=0? Если да - на выходjcxz exitнет - повторить циклjmp compareравно 0equal :вывод сообщения mes3 на экранmov ah,09hlea dx,mes3int 21hmov ah,02hmov dx.siadd dl,30hn-rtr\продолжение274Глава 13.
Сложные структуры данныхЛистинг 13.2 (продолжение)int 21hmov ah,09hlea dx,mes2int 21hinc esidec exjcxz exitjmp compareexit:mov ax,4c00hint 21hend main;вывод сообщения mes2 на экран;на следующий элемент;все элементы обработаны?;стандартный выход,;конец программыЕще несколько слов о соглашениях.it Если для описания адреса используется только один регистр, то речь идет о базовой адресации, и этот регистр рассматривается как базовый:;переслать байт из области данных,;адрес которой находится в регистре ebx:mov al,[ebx]ж Если для задания адреса в команде используется прямая адресация (в виде идентификатора) в сочетании с одним регистром, то речь идет об индексной адресации.
Регистр считается индексным, и поэтому для получения адреса нужногоэлемента массива можно выполнить масштабирование:add eax,mas[ebx*4];сложить содержимое еах с двойным словом;в памяти по адресу mas + (ebx)*4• Если для описания адреса используются два регистра, то речь идет о базовоиндексной адресации. Левый регистр рассматривается как базовый, правый —как индексный. В общем случае это не принципиально, но если масштабирование применяется к одному из регистров, то он всегда является индексным. Однако лучше придерживаться определенных соглашений.
Помните, что применение регистров ЕВР/ВР и ESP/SP по умолчанию подразумевает, что сегментнаясоставляющая адреса находится в регистре SS.Заметим, что базово-индексную адресацию не возбраняется сочетать с прямойадресацией или указанием непосредственного значения. Адрес тогда будет формироваться как сумма всех компонентов.К примеру,mov a x , m a s [ e b x ] [ e c x * 2 ];адрес операнда равен [mas+(ebx)+(ecx)*2]sub d x , [ e b x + 8 ] [ e c x * 4 ];адрес операнда равен [(ebx)+8+(ecx)*4]Следует заметить, что масштабирование эффективно лишь тогда, когда размерность элементов массива равна 2, 4 или 8 байт.
Если же размерность элементовдругая, то организовывать обращение к элементам массива нужно обычным способом, как описано ранее.Рассмотрим пример работы с массивом из пяти трехбайтовых элементов (листинг 13.3). Младший байт в каждом из этих элементов представляет собой некийсчетчик, а старшие два байта — что-то еще, для нас не имеющее никакого значе-Массивы275ния. Необходимо последовательно обработать элементы данного массива, увеличив значения счетчиков на единицу.Листинг 13.3. Обработка массива элементов с нечетной длиной;prg_13_3.asmMASHMODELsmall;модель памятиSTACK256;размер стека.data;начало сегмента данныхN=5;количество элементов массиваmas db 5 dup (3 dup (0)).code;сегмент кодаmain:;точка входа в программуmov ax,@datamov ds.axxor ax,ax;обнуление ахmov si ,0;0 в simov cx,N;N в схgo:mov dl.masfsi] ;первый байт поля в dlinc dlувеличение dl на 1 (по условию)mov mas[si],dl ;заслать обратно в массивadd si,3;сдвиг на следующий элемент массиваloop go;повтор циклаmov si,0подготовка к выводу на экранmov cx,Nshow:;вывод на экран содержимого;первых байтов полейmov dl,mas[si]add si , 3add dl,30hmov ah,02hint 21hloop showexi t:mov ax ,4c00h;стандартный выходint 21hendmain;конец программыДвухмерные массивыС представлением одномерных массивов в программе на ассемблере и организацией их обработки все достаточно просто.
А как быть, если программа должна обрабатывать двухмерный массив? Все проблемы возникают по-прежнему из-за того,что специальных средств для описания такого типа данных в ассемблере нет. Двухмерный массив нужно моделировать. На описании самих данных это почти никакне отражается — память под массив выделяется с помощью директив резервирования и инициализации памяти. Непосредственно моделирование обработки массива производится в сегменте кода, где программист, описывая алгоритм обработкина ассемблере, определяет, что некоторую область памяти необходимо трактоватькак двухмерный массив. При этом вы вольны в выборе того, как понимать расположение элементов двухмерного массива в памяти: по строкам или по столбцам.Если последовательность однотипных элементов в памяти трактуется как двухмерный массив, расположенный по строкам, то адрес элемента (i, j) вычисляетсяпо формуле(база + (количество_элементов_в_строке • i + j) • размер_элемента).276Глава 13.