C++ Developer • Cpp System Programming. HighLoad, Алгоритмы и Структуры данных. Разработка на Linux и Windows. STL, Boost, Qt и Embedded.

@cpp_lib
👨‍💻 Два в одном: валидация и вызов в Control Flow Guard (CFG) Рэймонд Чен (Raymond Chen) в своем блоге The Old New Thing поделился интересными деталями реализации механизма Control Flow Guard в Windows. Обычно CFG работает в два этапа: сначала мы вызываем функцию вроде LdrpValidateUserCallTarget для проверки указателя, и если всё в порядке, возвращаемся и делаем вызов. Но существует и комбинированная версия, которая не просто проверяет указатель, но и сразу же делает по нему переход (jump). 🤔 Зачем это нужно и в чем подвох? Раз уж после валидации почти всегда следует вызов, объединение операций кажется логичным шагом для оптимизации. Но здесь кроется проблема: для такого трюка приходится менять соглашение о вызовах (calling convention). Регистры, которые использует функция валидации, ни в коем случае не должны пересекаться с регистрами, в которых лежат аргументы для итоговой функции. 🔧 Как это реализовано на уровне ассемблера: 🔹 x86-64: Обычная функция-валидатор принимает адрес в rcx и использует rax и rdx как временные регистры. Комбинированная версия принимает адрес в rax, использует r10 и r11 для своих расчетов, а в конце просто делает jmp rax. Все исходные параметры целевой функции остаются нетронутыми! 🔹 AArch64: Логика абсолютно та же. Обычная версия принимает адрес в x15, а комбинированная - в x9, завершаясь инструкцией br x9 вместо классического ret. Кстати, есть и приятный микро-бонус при обработке ошибок: если указатель оказывается «битым», комбинированной функции не нужно тратить инструкции на перекладывание адреса в нужный регистр перед прыжком в блок ошибки - плохой адрес уже находится там, где нужно (rax или x9). 🔗 Оригинальная статья и листинги дизассемблера: https://devblogs.microsoft.com/oldnewthing/20260708-00/?p=112510 #cpp #programming 👉 @cpp_lib
Если у вас установлено приложение,
вы можете сразу перейти в канал