Префиксы в системе команд IA-32

от автора

Сегодня я хочу рассказать вам о префиксах в системе команд Intel IA-32 в 32- и 64-битных вариантах (также именуемых как x86 и x86_64). Но для начала напомню вкратце общую структуру IA-32 инструкции:

  • Префиксы. Могут отсутствовать. Может присутствовать сразу несколько.
  • Опкод. Может состоять из одного, двух или трех байтов.
  • Mod_R/M байт. Используется для адресации операндов. Может отсутствовать в кодировке, если инструкция не имеет явных операндов.
  • SIB (Scale Index Base) байт. Второй байт, использующийся для адресации операндов в памяти. Может отсутствовать.
  • Байт смещения адреса (англ. displacement). 1, 2, 4 или ни одного байта.
  • Константа (англ. immediate). 1, 2, 4 или ни одного байта.


Более подробное описание структуры инструкции можно найти в статье «Дизассемблер своими руками» и, конечно же, в Intel 64 and IA-32 Architectures Software Development Manuals. В данной статью будет рассказываться об IA-32 префиксах, особенностях, связанных с их использованием, а также тенденций в их развитии.

Однобайтные префиксы

Практически с самых первых процессоров Intel в системе команд IA-32 начали использоваться однобайтные префиксы. О них уже было написано на Хабре, по этой причине я про них рассказывать не буду.

Обязательные префиксы

С появлением расширения SSE часть однобайтных префиксов, а именно 0xf2, 0xf3, 0x66 в некоторых случаях стали иметь смысл части опкода. Появились так называемые обязательные префиксы (англ. mandatory prefixes). Примеры таких инструкций приведены ниже.

Кодировка Инструкция Обязательный префикс
0x0f 0x10 MOVUPS
0xf2 0x0f 0x10 MOVSD 0xf2
0xf3 0x0f 0x10 MOVSS 0xf3
0x66 0x0f 0x10 MOVUPD 0x66

Не сложно заметить, что кодировки этих инструкций отличаются только префиксом. Опкод у них совпадает – 0x0f 0x10. При этом семантика у этих инструкций различна. Например, MOVSD копирует из одного операнда в другой 64 бита, а MOVUPD – 128 бит.

Префикс REX

В определенный момент появилась необходимость в поддержке 64-битного адресного пространства и расширения числа адресуемых регистров. С этой задачей успешно справились разработчики AMD, добавив префикс, названный REX. Данный префикс также является однобайтными, и имеет вид 0x4*. Его биты используются для расширения уже существующих полей, кодируемых в Mod_R/M байте, а также ширины операнда. На рисунке приведен пример использования REX префикса для адресации регистров.

Стоит отметить несколько особенностей, связанных с использованием этого префикса. Кодировка 0x4* соответствует префиксу только в 64-битном режиме, во всех остальных режимах она соответствует вариантам инструкций INC/DEC. Интересным свойством данного префикса является то, что он должен быть расположен непосредственно перед байтом опкода, в противном случае он игнорируется. Если REX префикс используется вместе с инструкцией требующей присутствия другого обязательного префикса, он должен быть расположен между этим префиксом и байтом кода операции.

Префикс VEX

С введением расширения AVX в системе команд IA-32 появился новый префикс, названный VEX. Он уже не однобайтный. Он может состоять либо из двух, либо из трех байт в зависимости от первого байта префикса. 0xc4 и 0xc5 соответственно.

Поля R, X, B, W несут тот же смысл, что и соответствующие поля REX префикса. Поле pp предоставляет функциональность, эквивалентную обязательным SIMD префиксам (например, b01 = 0x66). А поле m-mmmm может соответствовать целым двум байтам опкода (например, 0b00011 = 0x0f 0x3a). Поле L определяет длину вектора: 0 – 128 бит, 1 – 256 бит.

Использование VEX префикса предоставляет следующие преимущества:

  • Поддержка до четырех операндов.
  • Поддержка 128-битных XMM регистров и 256-битных YMM регистров.
  • Сжатие кодировки уже введенных инструкций.
  • Удаление необходимости использования REX префикса для адресации регистров общего назначения (R8R15), векторных регистров XMM8XMM15 (YMM8YMM15). VEX позволяет кодировать те же поля, что и REX, и, вдобавок, несколько новых.

Следуют отметить, что использование VEX префикса вместе с некоторыми однобайтными префиксами (0xf0, 0x66, 0xf2, 0xf3, REX) запрещено и приводит к исключению #UD.

Префикс EVEX

Не так давно Intel анонсировал появление нового расширения набора команд с названием AVX3 или AVX512. С появлением этого расширения также появился и новый префикс, получивший название EVEX. Его описание можно найти в Intel Architecture Instruction Set Extensions Programming Reference.

Он представляет собой усовершенствованный вариант VEX префикса, имеет длину уже в 4 байта и начинается с байта 0x62, который во всех режимах, кроме 64-битного соответствует инструкции BOUND, редко используемой в современных программах.

Приведу некоторые, на мой взгляд, интересные особенности EVEX префикса:

  • Два бита для длины вектора – LL` – необходимые для поддержки векторов размером 128, 256 и 512 бит.
  • Поддержка адресации новых 512-битных регистров ZMM8ZMM31.
  • Поддержка регистров маски операндов (англ. opmask registers). Поле EVEX.aaa.
  • EVEX.mm – эквивалент поля VEX.m-mmmm, но занимает два бита вместо пяти.

Заключение

В заключение хочется отметить некоторые причины появления столько сложной и, местами, не логичной системы команд. История развития системы команд Intel IA-32 начинается в 70-х годах прошлого столетия, когда ни о каких 64-битных режимах не было и речи. Кроме Intel существенный вклад в эволюцию IA-32 внесла компания AMD. Много усилий было потрачено на поддержание обратной совместимости между различными моделями процессоров. Множество интересных фактов, связанных с развитием архитектуры IA-32 можно найти в статье A. Fog’a.

Спасибо пользователю Atakua за комментарии к черновикам этой статьи.

P.S. Все иллюстрации взяты из Intel 64 and IA-32 Architectures Software Development Manuals.

ссылка на оригинал статьи http://habrahabr.ru/company/intel/blog/200598/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *