Какова цель функции _chkstk ()? - PullRequest
27 голосов
/ 06 декабря 2011

Недавно я использовал опцию компилятора Visual C ++ /FAsu для вывода сборки source + особенно длинного определения функции-члена. В выводе сборки после установки фрейма стека происходит одиночный вызов таинственной функции _chkstk().

Страница MSDN на _chkstk() не объясняет причину, по которой вызывается эта функция. Я также видел вопрос переполнения стека Выделение буфера большего размера страницы в стеке приведет к повреждению памяти? , но я не понимаю, о чем говорят ОП и принятый ответ.

Какова цель функции _chkstk() CRT? Что это делает?

Ответы [ 2 ]

37 голосов
/ 06 декабря 2011

Страницы Windows в дополнительном стеке для вашего потока, как он используется.В конце стека есть одна защитная страница, отображаемая как недоступная память - если программа обращается к ней (потому что она пытается использовать больше стека, чем в настоящее время отображается), происходит нарушение доступа.ОС обнаруживает ошибку, сопоставляет другую страницу стека с тем же адресом, что и старая защитная страница, создает новую защитную страницу сразу за старой и возобновляет работу из инструкции, вызвавшей нарушение.

Еслифункция имеет более одной страницы локальных переменных, тогда первый адрес, к которому она обращается, может быть больше, чем на одну страницу за текущим концом стека.Следовательно, он пропустит страницу защиты и вызовет нарушение прав доступа, которое ОС не осознает, потому что требуется больше стека.Если требуемый общий стек особенно велик, он может даже выйти за пределы защитной страницы, за пределы конца виртуального адресного пространства, назначенного стеку, и в память, которая фактически используется для чего-то другого.

Итак,_chkstk гарантирует, что для локальных переменных достаточно места.Вы можете представить, что он делает это, касаясь памяти локальных переменных с интервалами размера страницы, в порядке возрастания, чтобы гарантировать, что он не пропустит защитную страницу (так называемые «проверки стека»).Я не знаю, действительно ли он это делает, хотя, возможно, он использует более прямой маршрут и дает указание ОС отображать определенный объем стека.В любом случае, если требуемый общий объем больше, чем виртуальное адресное пространство, доступное для стека, ОС может пожаловаться на это вместо выполнения чего-то неопределенного.

6 голосов
/ 07 апреля 2014

Я посмотрел код для __chkstk, и он выполняет повторные проверки стека с интервалами в одну страницу. Таким образом, не нужно делать никаких звонков в ОС. Параметр в rax - это размер данных, которые вы хотите добавить. Это гарантирует, что целевой адрес (текущий rsp - rax) доступен. Если rax> rsp, он делает это для адреса 0. Как интересный ярлык, он сначала сравнивает адрес с gs:[10h], который является текущей самой низкой отображаемой страницей; если целевой адрес> = this, то он ничего не делает.

Кстати, по крайней мере для 64-битного кода оно пишется с двумя подчеркиваниями: __chkstk__.

...