5.3. Режимы адресации
В архитектуре IA-32 определен большой и гибкий набор режимов адресации, используемых для доступа к отдельным элементам и областям памяти. Мы приведем полное описание этих режимов и способов их записи на языке ассемблера.
Основные режимы адресации, поддерживаемые большинством процессоров. Речь идет о непосредственной, абсолютной, регистровой и косвенной регистровой адресации. Абсолютная адресация, согласно терминологии Intel, называется прямой; так ее будем называть и мы. Существует несколько режимов адресации, обеспечивающих большую гибкость доступа к операндам, хранящимся в памяти компьютера. Самым гибким из режимов адресации, является индексный режим, обозначаемый как X(Ri,Rj). Исполнительный адрес операнда, EA, вычисляется в этом режиме так:
EA = [Ri] + [Rj] + Х
где Ri и Rj — это регистры общего назначения, базовый и индексный, а Х — константа, определяющая величину смещения. Среди режимов адресации процессоров IA-32 имеется несколько упрощенных разновидностей данного режима. Полный набор режимов адресации процессоров IA-32 таков.
Непосредственная адресация (immediate). Операнд содержится прямо в команде. Это 8-разрядное или 32-разрядное число, длина которого определяется соответствующим битом в поле кода операции. Для короткого операнда указанный бит равен 0, для длинного — 1.
Прямая адресация (direct). Адрес операнда в памяти определяется заданным в команде 32-разрядным значением.
Регистровая адресация (register). Операнд содержится в одном из восьми регистров общего назначения, заданном в команде.
Косвенная регистровая адресация (register indirect). Адрес операнда в памяти содержится в одном из восьми регистров общего назначения, заданном в команде.
Базовая со смещением (base with displacement). В команде определяются 8- или 32-разрядное смещение со знаком и один из восьми регистров общего назначения, используемый в качестве базового. Исполнительный адрес операнда равен сумме содержимого базового регистра и смещения.
Индексная со смещением (index with displacement). В команде задаются 32-разрядное смещение со знаком, один из восьми регистров общего назначения, который должен использоваться в качестве индексного, и коэффициент масштабирования — 1, 2, 4 или 8. Для получения исполнительного адреса операнда содержимое индексного регистра умножается на коэффициент масштабирования, а к результату прибавляется смещение.
Базовая индексная (base with index). В команде задаются два из восьми регистров общего назначения и коэффициент масштабирования — 1, 2, 4 или 8. Регистры используются как базовый и индексный, а исполнительный адрес операнда вычисляется следующим образом: содержимое индексного регистра умножается на коэффициент масштабирования, а к результату прибавляется содержимое базового регистра.
Базовая индексная со смещением (base with index and displacement). В команде задаются 8- или 32-разрядное смещение со знаком, два из восьми регистров общего назначения и коэффициент масштабирования — 1, 2, 4 или 8. Регистры используются как базовый и индексный, а исполнительный адрес операнда вычисляется следующим образом: содержимое индексного регистра умножается на коэффициент масштабирования, а результат складывается с содержимым базового регистра и смещением.
Синтаксис перечисленных режимов адресации процессоров IA-32 приведен в табл. 5.1. Кроме того, в ней показано, как вычисляется исполнительный адрес операнда для каждого из режимов. Согласно одной из сносок, регистр ESP не может использоваться в качестве индексного, поскольку, как вы увидите далее, он служит указателем на стек процессора. Ниже будет рассмотрено несколько примеров применения режимов адресации процессоров IA-32.
Таблица 5.1. Режимы адресации процессоров IA-32
Значение — 8- или 32-разрядное число со знаком.
Адрес — 32-разрядный адрес.
Reg,Reg1,Reg2 - один из регистров общего назначения (ЕАХ, ЕВХ, ЕСХ,EDX,ESP, ЕВР,ESI,EDI), с тем исключением, что регистр ESP не может использоваться в качестве индексного.
Disp— 8- или 32-разрядное число со знаком (смещение), с тем исключением, что смещение в режиме индексной адресации со смещением может быть только 32-разрядным. S — коэффициент масштабирования, равный 1, 2, 4 или 8.
Для иллюстрации режимов адресации удобно задействовать команду Move. Например, в команде
MOV ЕАХ,25
для пересылки десятичного значения 25 в регистр EAX применяется непосредственная адресация. По умолчанию заданное в такой форме число, состоящее из цифр от 0 до 9, интерпретируется как десятичное. Для обозначения двоичных и шестнадцатеричных чисел используются суффиксы В и Н. Например, команда
MOV EAX,3FA00H
пересылает в регистр EAX шестнадцатеричное число 3FA00.
В команде
MOV EAX,LOCATION
используется прямая адресация. Данная команда пересылает в регистр ЕАХ двойное слово из памяти по адресу, определяемому меткой LOCATION. При этом предполагается, что указанная метка определена как метка для адреса памяти в разделе объявлений программы на языке ассемблера. Из раздела 5.6 вы поймете, как это делается. Если метка LOCATION представляет адрес 1000, то данная команда пересылает в ЕАХ двойное слово, расположенное по адресу 1000.
Чуть позже мы поговорим о непосредственной и прямой адресации процессоров IA-32 более подробно, поскольку эти режимы часто путают. Возьмем такой случай. Иногда бывает полезно определить символические имена для числовых констант, задаваемых непосредственно в командах. Для назначения константам символических имен предназначена команда EQU, описанная в разделе 5.3. Например, команда
NUMBER EQU 25
связывает символическое имя NUMBER с десятичным числом 25. После этого команда
MOV EAX,NUMBER
интерпретируется ассемблером как операция пересылки в регистр ЕАХ непосредственно заданного операнда NUMBER. С другой стороны, если определить NUMBER как адресную метку, этот же операнд будет интерпретироваться как заданный при помощи прямого режима адресации.
Во многих языках ассемблера во избежание такой неоднозначности используется специальный символ, например «#», прибавляемый к числу в качестве префикса для обозначения непосредственной адресации. В языке ассемблера процессоров IA-32 для этой цели могут использоваться квадратные скобки:
MOV EAX,[LOCATION]
Однако если метка LOCATION определена как адресная, квадратные скобки не нужны.
При необходимости интерпретировать адресную метку как непосредственно заданный операнд можно воспользоваться ассемблерной директивой OFFSET. Так, команда
MOV EBX,OFFSET LOCATION
помещает значение адресной метки LOCATION, предположим 1000, в регистр ЕВХ с применением непосредственной адресации. После этого ЕВХ может использоваться в косвенном регистровом режиме адресации в команде
MOV ЕАХ,[ЕВХ]
пересылающей в регистр ЕАХ содержимое памяти по адресу LOCATION, содержащемуся в регистре ЕВХ. Слово OFFSET (смещение), выбранное для этой директивы языка ассемблера, подчеркивает, что адрес всегда интерпретируется как относительное расстояние от начальной точки сегмента памяти, содержащего операнд команды. Во всех приведенных выше примерах операнд назначения задавался в регистровом режиме адресации.
Мы проиллюстрировали использование четырех основных типов адресации:
непосредственной,
прямой,
регистровой и
косвенной регистровой.
Оставшиеся четыре режима предназначены для более гибкого доступа к операндам, хранящимся в памяти компьютера.
На рис. 5.6. показано, как используется режим базовой адресации со смещением. Базовым регистром здесь служит ЕВР. Двойное слово, расположенное на расстоянии 60 байт от базового адреса 1000, то есть по адресу 1060, можно переслать в регистр ЕАХ при помощи команды
MOV ЕАХ,[ЕВР+60]
Команды и режимы адресации процессоров IA-32 могут использоваться для работы, как с отдельными байтами, так и с двойными словами. Если в базовом регистре ЕВР содержится, скажем, адрес 1000, то для загрузки в младший байт регистра ЕАХ одного байта, хранящегося по адресу 1010, можно воспользоваться командой
MOV AL,[EBP+60]
Поскольку операнд назначения AL представляет собой младший байт регистра ЕАХ, ассемблер выберет код той операции пересылки, которая предназначена для пересылки байтов.
Рис. 5.6. Пример типа адресации в архитектуре IA-32.
Адресация базовая со смещением, заданная как [ЕВР+60]
Наиболее гибкой из всех адресаций является базовая индексная со смещением. Пример ее использования приведен на рис. 5.7., где функции базового и индексного регистров выполняют регистры ЕВР и ESI. Этот пример показывает, как обратиться к операнду, который является одним из элементов списка двойных слов. Список начинается со смещением 200 относительно базового адреса 1000. С использованием коэффициента масштабирования 4 для доступа к двойным словам по адресам 1200,1204,1208,... можно обращаться при помощи последовательности индексов 0,1, 2,... в индексном регистре ESI. В нашем случае в индексном регистре содержится значение 40 и при этом выполняется обращение к двойному слову по адресу 1360 (то есть 1000 + 200 + 4 х 40). Данный операнд загружается в регистр ЕАХ командой
MOV EAX,[EBP+ESI*4+200]
Использование коэффициента масштабирования облегчает доступ к последовательным двойным словам списка в программном цикле, поскольку в этом случае на каждом шаге цикла достаточно увеличивать значение индексного регистра на 1. Мы подробно обсудили два способа адресации, и теперь вы сможете понять, как функционируют сходные режимы адресации — индексная со смещением и базовая индексная.
Рис. 5.7. Пример типа адресации в архитектуре IA-32.
Адресация базовая индексная со смещением, заданная как [EBP+ESI*4+200]
Напоследок хотелось бы высказать одно замечание. Может показаться, что режим базовой адресации со смещением (табл. 5.1) является излишним, поскольку тот же результат можно получить при помощи индексной адресации со смещением с коэффициентом масштабирования 1. Однако команда с использованием первого режима на один байт короче. Кроме того, величина смещения во втором случае может задаваться только 32-разрядным числом.
В следующем разделе рассказывается о том, как описанные режимы адресации кодируются в машинных командах. Более подробная информация по данной теме приведена в [1].