Поделиться через


Предотвращение ошибок с плавающей запятой в пользовательских средах сборки

Эта информация предназначена для разработчиков и инженеров сборки, которые компилируют драйверы в режиме ядра для Windows. В Microsoft Visual Studio Professional 2012 архитектура по умолчанию для компилятора Visual C++ (VC++) изменилась с IA32 на набор инструкций Streaming SIMD Extensions 2 (SSE2). В результате этого изменения инструкции SSE2 с плавающей запятой (FP), внедренные в двоичный файл во время компиляции, могут создавать ошибки с плавающей запятой, если они не учитываются. Эта проблема может возникнуть у тех, кто использует компилятор Microsoft VC++ или настраиваемую среду сборки для разработки драйверов Windows. Однако проблема не влияет на разработчиков, использующих среду разработки Microsoft Visual Studio, или которые используют служебную программу MSbuild для создания драйверов с немодифицированным набором инструментов.

Ошибки с плавающей запятой могут привести к повреждению данных или зависаниям компьютера

Если вы компилируете драйвер без использования WDK, Visual Studio и рекомендуемого набора инструментов платформы для драйверов Windows (WindowsKernelModeDriver8.0), драйвер может не управлять операциями с плавающей запятой, даже если драйвер компилируется без ошибок.

Компилятор Visual Studio Professional 2012 VC++ выдает код, который использует набор инструкций SSE2, задав параметр компилятора /arch:sse2 . Начиная с Visual Studio Professional 2012, это параметр по умолчанию для создания кода компилятора x86 VC++. В частности, значение по умолчанию изменяется с /arch:ia32 на /arch:sse2.

Для приложений это изменение создает код, который работает лучше и использует меньше времени процессора во время выполнения. Однако для драйверов в режиме ядра это изменение не будет корректно управлять состоянием с плавающей запятой (FP). Это связано с тем, что компилятор VC++ вводит последовательности инструкций FP в местах, где контекст не сохранен. Любая двоичная система с числом с плавающей запятой может представлять только конечное число значений с плавающей запятой в точной форме, а остальные — приблизительные. Состояние управления с плавающей запятой, например режим округления или точность, — это то, что обеспечивает синхронизацию операций FP друг с другом. Если состояние не определено, это приводит к ошибкам вычисления FP. Эти ошибки вычисления трудно обнаружить, так как в большинстве случаев повреждение состояния приложения является единственным признаком этой проблемы. Эта коррупция может проявляться различными способами, начиная от случайных сбоев до повреждения данных.

решение

Чтобы избежать этой проблемы при вычислениях с плавающей запятой, добавьте флаг /kernel в командную строку компилятора C++ и компоновщика, чтобы предотвратить создание инструкций SSE2. Флаг / kernel изменяет значение по умолчанию /arch:sse2 обратно на /arch:ia32.

Кроме того, если вы создаете драйвер с помощью WDK и среды разработки Visual Studio Professional 2012 или используете MSBuild в окне командной строки Visual Studio, предоставленный Microsoft набор инструментов платформы (WindowsKernelModeDriver8.0) задает флаг /kernel. В результате избегаются ошибки, связанные с генерацией чисел с плавающей запятой.

msbuild myProject.vcxproj /p:PlatformToolset=WindowsKernelModeDriver8.0

Рекомендации

Ниже приведены рекомендуемые решения на основе типа используемой среды разработки:

  • Набор инструментов Майкрософт (MSBuild) — работа не требуется. Используйте WindowsKernelModeDriver8.0 в качестве набора инструментов платформы, /kernel добавляется автоматически в соответствующих случаях.
  • Компилятор Microsoft VC++ — добавьте флаг /kernel, чтобы предотвратить генерацию SSE2 компилятором.
  • Пользовательские инструменты/компилятор не от Microsoft – необходимо вручную учесть инструкции по сборке, используемые в результирующем двоичном файле.