company_banner

Префиксы в системе команд 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.

    Intel

    144,00

    Компания

    Поделиться публикацией
    Комментарии 11
      0
      А уже все префиксы «заняты», что отбирают у редких команд?
        +1
        Речь о том, что команду BOUND не стали переносить в 64-битную архитектуру, поэтому место освободилось.
        Двубайтных опкодов, до сих пор неиспользованных, предостаточно; а вот однобайтные, как у BOUND — дефицит.
          0
          Там не один десяток команд «не стали переносить», но Intel до сих пор успешно выпускает процессоры без поддержки 64-битного режима, так что использовать это они ещё долго не решатся.

          P.S. Кстати AMD использует похожую на VEX схему, только у них она называется XOP и начинается с 8f.
            +1
            Да нет же. AVX3 появится уже в Knights Landing. Вот, посмотрите сюда.

            Intel AVX-512 will be first implemented in the future Intel® Xeon Phi™ processor and coprocessor known by the code name Knights Landing


            На сколько я знаю, расширение SSE5, в котором появились XOP префиксы, было анонсировано даже раньше, чем AVX с VEX префиксами. Но AVX оказался более гибким и удобным, поэтому AMD оказалось вынужденным поддерживать AVX, тогда как Intel не стал поддерживать SSE5.
          0
          Сейчас в системе команд IA-32 больше тысячи инструкций. Однобайтных кодов всего 2^8 = 256, и все они уже давным давно заняты. Поэтому их действительно дефицит.

          Например, когда-то байт 0x0f соответствовал инструкции POP CS, которая никогда не использовалась. Его начали использовать как код, соответствующий первому байту двухбайтовых инструкций, тем самым добавив еще 256 возможных кодировок.
            +1
            INC и DEC все таки использовались, почему их не перенесли, не вкурсе?
              +1
              Для меня это тоже остаётся загадкой. С другой стороны, альтернативные, более современные варианты INC/DEC, использующие ModRM для кодирования регистра/памяти, остались и в 64-битном режиме и могут использовать тот же REX. 0x40/0x48 способны только регистр адресовать.
                0
                Видимо, из-за соотношения cost/benefit: сочли неоправданным тратить 1/16 всего пространства опкодов на пару инструкций, которые используются ну уж не настолько часто.
                  0
                  Мне все-таки кажется, что на это решение повлияло именно присутствие аналогичных и более совершенных инструкций. Тем более, что поддержка старых вариантов INC и DEC осталось во всех режимах, кроме 64-битного.
                  0
                  Скорее всего, чтобы упростить декодер. REX-префиксы расположены плоной группой, достаточно провверить старший nibble, чтобы понять что перед вами REX, а если бы то же самое сотворили с кучей дыр, оставшихся от нереализованных в x86-64 команд, то декодер было бы делать куда сложнее.
              +2
              Эх, мне больше нравится ISA RISC процессоров — где операторы фиксированной длины. Хотя это и ведет к некоторому разбуханию кода — например, когда надо сделать far jmp

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое