Подтвердить что ты не робот

Как включить исключения выравнивания для моего процесса на x64?

Мне интересно узнать, страдает ли мое 64-битное приложение от ошибок выравнивания.

От Выравнивание данных Windows на IPF, x86 и x64:

В Windows прикладная программа, которая генерирует ошибку выравнивания, создаст исключение, EXCEPTION_DATATYPE_MISALIGNMENT.

  • В архитектуре x64 исключения выравнивания по умолчанию отключены, а исправления выполняются аппаратным обеспечением. Приложение может включить исключения выравнивания, установив пару бит регистра, и в этом случае исключения будут подняты, если у пользователя нет операционной системы, маскировка исключений с помощью SEM_NOALIGNMENTFAULTEXCEPT. (Подробнее см. Руководство программиста AMD Architecture Volume 2: Системное программирование.)

[Под ред. акцент мой]

  • В архитектуре x86 операционная система не делает видимость выравнивания видимой для приложения. На этих двух платформах вы также понесете ухудшение производительности при сбое выравнивания, но оно будет значительно менее серьезным, чем на Itanium, поскольку аппаратное обеспечение сделает множественный доступ к памяти для получения неуравновешенных данных.

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

Не обращая внимания на руководство, проконсультирующееся с Руководством по программированию архитектуры AMD, я вместо этого проконсультирую Intel 64 и IA-32 Architectures Software Руководство для разработчиков

5.10.5 Проверка выравнивания

Когда CPL равно 3, выравнивание ссылок на память можно проверить, установив Флаг AM в регистре CR0 и флаг AC в регистре EFLAGS. Unaligned memory Ссылки генерируют исключения выравнивания (#AC). Процессор не генерирует исключения выравнивания при работе на уровне привилегий 0, 1 или 2. См. таблицу 6-7 для описание требований к выравниванию, когда проверка выравнивания включена.

Отлично. Я не уверен, что это значит, но отлично.

Тогда также:

2.5 РЕГИСТРЫ УПРАВЛЕНИЯ

Контрольные регистры (CR0, CR1, CR2, CR3 и CR4, см. Рисунок 2-6) определяют работу режим процессора и характеристики выполняемой в настоящее время задачи. Эти регистры составляют 32 бита во всех 32-битных режимах и режиме совместимости.

В 64-битном режиме регистры управления расширяются до 64 бит. Инструкции MOV CRn используются для управления битами регистра. Префикс размера операнда для этих инструкций игнорируются.

Регистры управления суммированы ниже, и каждый установленный по архитектуре элемент управления поле в этих контрольных регистрах описывается индивидуально. На рисунке 2-6 ширина регистр в 64-битном режиме указывается в скобках (кроме CR0). - CR0 - содержит флаги управления системой, которые управляют режимом работы и состояниями процессор

enter image description here

AM
Маска выравнивания (бит 18 из CR0) - позволяет автоматическую проверку выравнивания когда установлено; отключает проверку выравнивания при очистке. Проверка выравнивания выполняется только тогда, когда установлен флаг AM, флаг AC в регистре EFLAGS set, CPL - 3, а процессор работает либо в защищенной, либо в виртуальной среде, 8086.

Я пробовал

Язык, на котором я фактически использую, - это Delphi, но притворяйтесь, что это язык агностический псевдокод:

void UnmaskAlignmentExceptions()
{
   asm
      mov rax, cr0; //copy CR0 flags into RAX
      or  rax, 0x20000; //set bit 18 (AM)
      mov cr0, rax; //copy flags back
}

Первая инструкция

mov rax, cr0;

не работает с привилегией привилегированной инструкции.

Как включить исключения выравнивания для моего процесса на x64?

PUSHF

Я обнаружил, что x86 имеет инструкцию:

  • PUSHF, POPF: Вставить/поместить первые 16 бит EFLAGS вкл/выкл стека
  • PUSHFD, POPFD: нажмите/поместите все 32-бит EFLAGS вкл/выкл

enter image description here

Это привело меня к версии x64:

  • PUSHFQ, POPFQ: нажмите/введите RFLAGS quad вкл/выкл

(В 64-битном мире EFLAGS переименованы RFLAGS).

Итак, я написал:

void EnableAlignmentExceptions;
{
    asm
       PUSHFQ;                //Push RFLAGS quadword onto the stack
       POP       RAX;         //Pop them flags into RAX
       OR        RAX, $20000; //set bit 18 (AC=Alignment Check) of the flags
       PUSH      RAX;         //Push the modified flags back onto the stack
       POPFQ;                 //Pop the stack back into RFLAGS;
}

И это не привело к сбою или срабатыванию исключения защиты. Я не знаю, делает ли он то, что я хочу.

4b9b3361

Ответ 1

Приложения, работающие на x64, имеют доступ к регистру флагов (иногда называемому EFLAGS). Бит 18 в этом регистре позволяет приложениям получать исключения, когда возникают ошибки выравнивания. Таким образом, теоретически, вся программа должна делать, чтобы разрешить исключения для ошибок выравнивания - изменить регистр флагов.

Однако

Чтобы это действительно работало, ядро ​​операционной системы должно установить cr0 бит 18, чтобы разрешить это. И операционная система Windows этого не делает. Почему нет? Кто знает?

Приложения не могут устанавливать значения в регистре управления. Только ядро ​​может это сделать. Драйверы устройств запускаются внутри ядра, поэтому они также могут установить это.

Можно отбросить и попытаться заставить это работать, создав драйвер устройства (см. http://blogs.msdn.com/b/oldnewthing/archive/2004/07/27/198410.aspx#199239 и последующие комментарии). Обратите внимание, что этот пост старше десятилетия, поэтому некоторые ссылки мертвы.

Вы также можете найти этот комментарий (и некоторые другие ответы в этом вопросе), чтобы быть полезным:

Ларри Остерман - 28-28-2004 2:22 утра

На самом деле мы построили версию NT с исключениями выравнивания, включенными для x86 (вы можете сделать это, как упоминалось Skywing).

Мы быстро отключили его из-за количества сломанных приложений.

Ответ 2

Это работает в 64-битном процессоре Intel. Может произойти сбой в некоторых AMD

pushfq
bts qword ptr [rsp], 12h ; reset AC bit of rflags
popfq

Он не будет работать сразу в 32-разрядных процессорах, для этого сначала потребуется драйвер ядра для изменения бита AM CR0, а затем

pushfd
bts dword ptr [esp], 12h
popfd