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

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

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

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

MOV EDX, EAX

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

MOV CL, 654

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

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

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

x dd 56

y dd –37

z dd 0

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

MOV eax, [x]

ADDeax, [y]

MOV [z], eax

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

z = x + y

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

MOV eax, [00000020]

ADDeax, [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 должен быть записан числом, или путем использования рассмотренной выше и записанной где-то в программе директивы

neq u число

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

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. Это далеко не идеальное решение. Если имя области данных именует область неоднородной – с точки зрения программиста – структуры, то использование обозначения вида [имя_области + число] естественно для доступа к части фактической структуры, но автоматически приобретает атрибут начального поля в такой структуре.

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