Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Флоренсов А.Н. УП Системное программное обеспечение.docx
Скачиваний:
46
Добавлен:
28.06.2021
Размер:
148.95 Кб
Скачать

4.3. Базовая и индексно-базовая адресации

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

Для пояснения существа использования базовой адресации будем исходить из следующего описания на языке Си:

struct doca {

char sex;

int age;

charname[10];

};

struct doca persons[20];

которое в упрощенном варианте подготавливает массив структур данных для учетной информации о некоторых людях (пол, возраст и имя).

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

Если отдельно описать строение данной структуры на ассемблере, мы получим следующее:

; struct doca

sex DB 0

age DD 0

name TIMES 10 DB 0

Простейшее решение заключается в использовании численных смещений от начала структуры. Непосредственно видно (в том числе из листинга соответствующей программы), что поле sex находится с нулевым смещением от начала экземпляра структуры, поле age – на расстоянии одного байта от начала экземпляра структуры, а поле name, соответственно, на расстоянии пяти байт от начала структуры (считая, что данные типа int требуют для записи в 32-битной архитектуры четыре байта).

Технической и в некоторой степени языковой проблемой для ассемблера является то, что эти поля нужно обозначать и использовать для любого из экземпляров в массиве структур. Базовый способ адресации и позволяет тут же решить эту задачу. Предварительно в некоторый регистр, называемый далее базовым в операнде с рассматриваемой адресацией, заносится значение адреса экземпляра структуры. Тогда обозначение [базовый_регистр+0] задает в операнде команды поле sex, обозначение [базовый_регистр+1] задает поле age, а обозначение [базовый_регистр+5] задает поле name. (С помощью последнего обозначения можно добраться до одного, двух или четырех начальных байтов поля name, используя, соответственно, модификаторы byte, word и dword.) Меняя значение в регистре базовый_регистр, можно с помощью одной и той же команды добираться до одноименного поля в различных экземплярах структуры.

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

Например, для вычисления суммы значений полей age в предложенном выше примере (для вычисления среднего возраста или чего-то подобного) можно использовать следующий фрагмент программы на ассемблере

mov ebx, persons ; адрес массива структур заносится в ebx

mov ecx, 20

mov eax, 0; регистр EAX предназначен для вычисляемой суммы

povt: add eax, [ebx+1] ; прибавление значения поля age

add ebx, 15 ; увеличение регистра ebx на размер структуры doca

loop povt

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

Для описания всего массива данных может быть использована «очень слепая» форма записи в виде

persons TIMES 20*15 db 0

или же более развернутая для программиста форма, применяющая директиву повторения REP

persons

%rep 20

DB 0

DD 0

TIMES 10 DB 0

%endrep

Эта директива относится к средствам предпроцессора (предварительной до собственно компилятора обработки исходного текста). Она с помощью начальной части конструкции %rep задает число повторений идущего далее текста – до строки с ключевым словом %endrep. В данном случае 20 раз повторяется описание полей для структуры.

Более мощным средством являются предпроцессорные директивы описания структуры данных. Они задаются ключевыми словами STRUC и ENDSTRUC, указывающими начало и конец описания структуры, причем имя структуры задается как единственный параметр в директиве STRUC. Само описание при этом должно задаваться исключительно резервированием памяти. В нашем примере мы получаем

struc doca

sex resb 1

age resd 1

name resb 10

endstruc

Такое введение в использование имен полей sex, age, name равносильно явному заданию для каждого из них числового значения, равного смещению соответствующего поля относительно начала структуры. В данном случае неявно для поля sex задается значение 0, для поля age – значение 1, для поля name – значение 5. После этого можно в операндах, указывающих доступ к этим полям, записывать соответственно[ebx+sex], [ebx+age], [ebx+name].

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

struc doca

.sex resb 1

.age resd 1

.name resb 10

endstruc

то имена .sex, .age, .name будут относиться только к структуре doca. Определенные таким образом имена полей должны использоваться вместе с именем структуры в виде имя_структуры.имя_поля. Все это сделано, чтобы можно было применять одноименные поля в различных структурах данных, которые различаются именно по квалификатору имени структуры, стоящему перед именем поля.

В нашем последнем примере обозначение поля sex в операнде, который в качестве базового использует регистр ebx, должно записываться в виде [ebx+doca.sex], использование поля age – в виде [ebx+doca.age], а поля name – в виде [ebx+doca.name]. Еще раз подчеркнем, что вместо таких достаточно наглядных, но более длинных обозначений программист может использовать просто числовое значение смещения.

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

[базовый_регистр+индексный_регистр+смещение]

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

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

mov ebx, persons ; адрес массива структур заносится в ebx

mov ecx, 20

povt: mov esi, 0 ; нулевой индекс в esi для доступа к нач. байту области

iname: . . .использование байтов области name

; . . . с помощью операнда в виде [ebx+esi+5]

inc esi ; индекс в esi переустановить на след.элемент в массиве name

cmp esi, 10

jl iname

add ebx, 15 ; увеличение регистра ebx на размер структуры doca

loop povt

Здесь, как уже указывалось выше, обозначение доступа к байту в массиве name может быть записано в виде[ebx+esi+doca.name], но только если в программе директивой предпроцессора определено строение структуры doca.

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