Comments 10
Как это применяется на практике? На ум приходит только динамический стек в среде выполнения какого-нибудь языка, когда нужно добавить памяти и продолжить. В остальных случаях логика "у нас нарушен инвариант, но мы его восстановим в фоне и как-нибудь продолжим" выглядит очень сомнительно. А обработчики, зависящие от того, как скомпилируется код, хрупкие и сложные.
Как это применяется на практике?
Например, при реализации отладчика - продолжение выполнения при достижении программной точки останова (int 3). Выполнив инструкцию int 3, попадаем в обработчик (остановились, делаем, что нужно, например, смотрим значения в регистрах). Для продолжения выполнения перезаписываем установленный breakpoint исходными данными (разумеется они должны быть ранее сохранены) и снова выполняем инструкцию, вызвавшую исключение. Теперь выполняется код уже без breakpoint'a и выполнение идет дальше, например, до следующей точки останова.
Еще как вариант, для выполнения запрещенных команд, погрузки страниц в легковесном эмуляторе. Но сейчас, я думаю, это не так актуально, наверное, так как есть wsl.
Для того, чтобы функция CustomFilter работала для обоих разрядностей (x86 и x64) можно воспользоваться директивами условной компиляции
Совершенно не понятно, почему вы ассоциируете разницу в коде с разрядностью платформы. Разрядность платформы тут совершенно ни при чем, а все зависит от настроек кодогенератора и в первую очередь от настроек оптимизации. Зависимость от разрядности платформы - это не более чем паразитная/случайная зависимость. И судя по вашим экспериментам, вы выполняли их в отладочной конфигурации, что является весьма странной затеей.
Это проблему такими директивами условной компиляции не решить. Или, точнее, это будет "решение", которое очень запросто "превратится в тыкву" в самый неожиданный момент.
https://habr.com/ru/post/682958/#:~:text=Разрядность платформы тут совершенно ни при чем
Не соглашусь. Например, поля структуры EXCEPTION_POINTERS будут иметь различные имена и смещения в x86 и x64.
а все зависит от настроек кодогенератора и в первую очередь от настроек оптимизации
Разумеется, создаваемый машинный код будет зависеть и от этого. В данной статье я привел пример с анализом машинного кода для конкретного описанного случая и соответствующей настройкой в обработчике исключения.
Или, точнее, это будет "решение", которое очень запросто "превратится в тыкву" в самый неожиданный момент.
Разумеется, при пересборке с другими параметрами компилятора, без анализа сгенерированного машинного кода данное решение работать не будет.
Остался не раскрыт вопрос, как оно всё работает на суперскалярном процессоре. Когда в момент сбоя проблемой инструкции успели выполниться пара других параллельно. Процессор должен как-то "откатить" результат, что представляется нетривиальной задачей.
Спекулятивное выполнение и теневые регистры же. Вас же не удивляет, что обе ветки if-else выполняются, а когда результат условия становится известен, выбирается только один путь. Спекуляций видимых за MMU/IOMMU видимо все-таки не существует по определению (Кроме хитрых lockless алгоритмов, но там другое - алгоритм умеет rollback-ить определенные жестко фиксированные случаи, которые сам же и спекулирует :)
А точно обе ветки if else выполняются? Вроде, branch predictor выбирает брать переход или нет. Выполнение обеих веток обычно в VLIW процессорах делается.
Могу ошибаться, поэтому прошу скинуть ссылку на материал, который докажет, что типичный x86-64 процессор выполняет обе ветки, а затем отбрасывает результат той ветки, которую брать не надо.
Разбираемся с EXCEPTION_CONTINUE_EXECUTION