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

2.5. Простейшие способы адресации

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

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

MOV EDX, EAX

оба ее операнда заданы регистровым способом адресации, а в команде

MOV CL, 654

левый операнда задан регистровым способом адресации, а правый - другим способом.

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

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

x dd 56

y dd -37

z dd 0

тогда команды

MOV eax, [x]

ADD eax, [y]

MOV [z], eax

обеспечивают сложения значений из 4-х байтовых полей данных с именами x и y с последующим помещением результата в двойное слово области z. Практически эти команды реализуют оператор Си

z = x + y

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

MOV eax, [00000020]

ADD eax, [00000024]

MOV [00000028], eax

отражающие, в частности, тот факт, что именованные в исходном файле области x, y, z в сегменте данных исполняемого файла будут находиться со смещениями 20, 24 и 28 от начала этого сегмента. Именно поэтому для обозначения на ассемблере данных в памяти компьютера используются вспомогательные синтаксические элементы - квадратные скобки. Убрав скобки из последнего фрагмента команд, мы бы получили, что первая команда приказывает занести числовую константу 20 в регистр eax, а вторая команда приказывает прибавить к содержимому регистра eax значение числовой константы 24. Последние приказания совершенно отличны от задаваемых в исходном файле действий, где область данных, наименованная x, содержит число 56, а область данных, наименованная y, содержит число -37. Другое дело, что область, ранее обозначенная x, в машинном коде обозначается просто как лежащее со смещением 20 от начала сегмента данных, а область, ранее обозначенная как y, лежит со смещением 24 от начала сегмента данных. (Заметим, что в языках высокого уровня никогда не появляются действительные обозначения переменных числовыми смещениями от начала сегмента и, поэтому нет никакой необходимости вводить специальные символы, подчеркивающие, что имя обозначает место в памяти, а не само значение, как бывает для констант, размещаемых внутри кода команды.)

С точки поверхностного программирования действие команды

MOV edx, 127

равносильно действию команды

MOV edx, [kkk]

где имя kkk определено в сегменте данных как

kkk dd 127

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

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

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

; Ввод строки текста, изменение в ней второго из введенных на символ ! и

; вывод полученной строки

GLOBAL _start

SEGMENT .text

_start:

;--- read(1, buf, 80 == <3>(ebx, ecx, edx)

mov eax,3 ; N function=read

mov ebx,0 ; 0 handle=0 (stdin)

mov ecx, buf ; address of buf

mov edx,80 ; number of byte

int 80h

mov [len],eax

mov byte [buf+1],'!'

;--- write(1, buf, [len]) == <4>(ebx, ecx, edx)

mov eax,4h ; N function=write

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

mov ecx, buf ; address of buf

mov edx,[len] ; number of byte

int 80h

mov eax,1

int 80h ; function=exit

SEGMENT .data

buf times 80 db 0 ; или resb 80; но тогда будет предупреждение

len dd 0

Листинг 2.5.1. Простейшее использование прямой адресации

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

Для доступа ко второму байту (считая, что начальный байт области называется первым) используется также прямой способ адресации, записываемый в операндах в виде

[buf+1]

Если мы запишем в операнде [buf+0], то попадем на самое начало области, что равносильно записывается как [buf], для обозначения 10-го байта в этой области достаточно записать операнд в виде [buf+9]. Заметим, что в профессиональном программировании целесообразно нумеровать элементы массива и, в частности, байты области данных, начиная с нуля, так что n-й байт области данных с именем obl обозначится в операнде команды как [obl+n], где элемент n должен быть записан числом или путем использования рассмотренной выше и записанной где-то в программе директивы

n equ число

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

MOV [xxx], -127

не может быть компилятором ассемблера NASM преобразован в машинный код, даже при правильно определенной области данных xxx (например, с помощью директивы xxx DD 0), потому что непонятно, сколько байтов двоичного кода требуется поместить в качестве значения константы -127: 8 битов, 16 битов или все 32 бита. (Если человеческие записи чисел не используют нулевых цифр перед первой значащей цифрой, то в машинных структурах совсем наоборот, более того, машинные способы записи отрицательных чисел в первом случае требуют запомнить шестнадцатеричный код 7F, во втором - FF7F, а в третьем - FFFFFF7F.) Для решения проблемы однозначной определенности в ассемблеры введены дополнительные средства. В ассемблере NASM они представляют собой модификаторы разрядности, задаваемые служебными словами BYTE, WORD и DWORD. Эти модификаторы ставятся перед теми операндами, разрядность которых необходимо уточнить. В частности, вместо недоопределенной выше команды имеется возможность для указанных вариантов задать одну из следующих команд:

MOV BYTE [xxx], -127

MOV WORD [xxx], -127

MOV DWORD [xxx], -127

В ассемблерах MASM и TASM принята другая методология использования имен данных. Согласно возвышенным принципам, заложенным в эти ассемблеры, именам данных соотносятся не только значения, задаваемые смещением начала именованных данных относительно начала сегмента, но и атрибуты. К этим атрибутам относят имя сегмента, в котором данные определены, и характеристику размера. Эти характеристики обозначаются служебными словами BYTE, WORD и DWORD (и рядом других). Поэтому в этих ассемблерах запись команды в виде

MOV [xxx], -127

интерпретируется по-разному в зависимости от определения имени xxx. На самом деле это далеко не идеальное решение, так как, во-первых, значение имени может быть задано директивой EQU и тогда вступает далеко не явное допущение. Во-вторых, иногда возникает необходимость область данных, определенную одним размером, частично заполнить данными меньшего размера (например, младшую и старшую половину отдельными командами). Если имя области данных на самом деле именует область неоднородной - с точки зрения программиста - структуры, то использование обозначения вида [имя_области + число] естественно для доступа к части фактической структуры, но автоматически приобретает атрибут начального поля в такой структуре.

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

С учетом отмеченной необходимости и в MASM, TASM явно задавать размер операндов там, где это необходимо или при желании отказаться от решения по умолчанию, в эти ассемблеры также введены средства явного задания размера операндов. К сожалению, высокие соображения привели к более сложным конструкциям. Для задания размеров в 8, 16 и 32 бита предназначены обозначения BYTE PTR, WORD PTR и DWORD PTR, так что на этих ассемблерах описанные выше примеры запишутся как

MOV BYTE PTR [xxx], -127

MOV WORD PTR [xxx], -127

MOV DWORD PTR [xxx], -127

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

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