Как стать автором
Обновить

Комментарии 9

Как это применяется на практике? На ум приходит только динамический стек в среде выполнения какого-нибудь языка, когда нужно добавить памяти и продолжить. В остальных случаях логика "у нас нарушен инвариант, но мы его восстановим в фоне и как-нибудь продолжим" выглядит очень сомнительно. А обработчики, зависящие от того, как скомпилируется код, хрупкие и сложные.

Как это применяется на практике?

Например, при реализации отладчика - продолжение выполнения при достижении программной точки останова (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 процессор выполняет обе ветки, а затем отбрасывает результат той ветки, которую брать не надо.

Сути это не меняет. Предиктор ошибся - процессор вынужден откатиться и начать исполнение с другой ветки.
А по факту отсутствия одновременного исполнения - тут похоже вы правы. Иначе не работала бы атака Spectre.

Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории