Мне интересно узнать, страдает ли мое 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 - содержит флаги управления системой, которые управляют режимом работы и состояниями процессор
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 вкл/выкл
Это привело меня к версии 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;
}
И это не привело к сбою или срабатыванию исключения защиты. Я не знаю, делает ли он то, что я хочу.