Что делает флаг D в дескрипторе сегмента кода для инструкций x86-64?

Я пытаюсь понять, как работает D flag в дескрипторе сегмента кода при использовании в коде x86-64. Он установлен в D/B бите 22 дескриптора сегмента кода, как показано на этой диаграмме:

введите здесь описание изображения

Документация Intel (из раздела 3.4.5 Дескрипторы сегмента) утверждает следующее:

введите здесь описание изображения

Флаг D / B (размер операции по умолчанию / размер указателя стека по умолчанию и / или верхняя граница)

Выполняет разные функции в зависимости от того, является ли дескриптор сегмента сегментом исполняемого кода, сегментом раскрываемых данных или сегментом стека. (Этот флаг всегда должен быть установлен в 1 для 32-битных сегментов кода и данных и в 0 для 16-битных сегментов кода и данных.)

• Сегмент исполняемого кода. Флаг называется флагом D и указывает длину по умолчанию для эффективных адресов и операндов, на которые ссылаются инструкции в сегменте. Если этот флаг установлен, предполагается, что 32-битные адреса и 32-битные или 8-битные операнды; если он ясен, предполагается, что 16-битные адреса и 16-битные или 8-битные операнды. Префикс инструкции 66H может использоваться для выбора размера операнда, отличного от значения по умолчанию, а префикс 67H может использоваться для выбора размера адреса, отличного от значения по умолчанию.

Вот и пытаюсь понять, на какие инструкции x86-64 это влияет и как?

PS. Когда я пытаюсь запустить некоторые тесты (в ядре Windows), установив этот бит, ОС сразу же утроит ошибку.


person MikeF    schedule 13.07.2018    source источник


Ответы (1)


Если L (длинный режим) установлен для дескриптора сегмента кода, D должен быть очищен. Комбинация L = 1 / D = 1 в настоящее время не имеет смысла / зарезервирована. Intel документирует это поблизости в том же документе, который вы просматривали.

Если L очищен, то D выбирает между 16- и 32-битным режимом. (т.е. размер операнда / адреса по умолчанию). И да, 16-битный защищенный режим есть, но нет, им никто не пользуется.


Есть только 3 возможности для адреса / размера операнда по умолчанию:

  • 16-битные режимы (реальный, vm86, защищенный): адрес по умолчанию и размер операнда = 16 бит
  • 32-битный защищенный режим: адрес по умолчанию и размер операнда = 32-битный
  • 64-битный режим: размер адреса по умолчанию = 64-бит, размер операнда по умолчанию = 32-бит

Нет возможности иметь 16x 64-битных регистров, но размер операнда по умолчанию - 16-битный или 64-битный. Или размер адреса по умолчанию 32-битный, с возможностью переопределения до 64.

person Peter Cordes    schedule 13.07.2018
comment
О, так то, что я делал, установив бит L, а также установив бит D, было незаконным, и именно поэтому я получал тройную ошибку, верно? - person MikeF; 13.07.2018
comment
Но держись. Прочитав документацию Intel еще раз (ту, что я показал выше) - почему они упоминают префиксы 66H и 67H в том же абзаце, где обсуждают флаг D для исполняемого кода? Эти префиксы работают только в 64-битном длинном режиме, когда в дескрипторе сегмента кода установлен флаг L. Итак, если в этом случае необходимо сбросить флаг D, почему они поднимают эти префиксы? Это то, что меня смущает. - person MikeF; 13.07.2018
comment
@MikeF: Нет, это префиксы REX только для длинного режима. Префиксы размера операнда меняются между 16 и 32 битами в 32-битном режиме так же, как в 64-битном режиме, или наоборот в 16-битном режиме. (например, add eax,eax требуется префикс 66H в 16-битном режиме, но не в 32 или 64.) Посмотрите на некоторый вывод ассемблера для add eax, [esi] vs. add ax, [si] в 16-битном или 32-битном режиме. (например, запустите nasm -l, чтобы составить список, включающий машинный код) - person Peter Cordes; 14.07.2018