Информация об изменениях

Сообщение Re[7]: особенности структурной обработки исключений в Win64 от 03.12.2016 19:41

Изменено 03.12.2016 19:48 ononim

O>>Дебажные символы. windbg настраивается на публичный микрософтовский символ-сервер двумя командами: .symfix и .reload
O>>С чего вы взяли что сохранение бездумное, а функция простейшая? Что за код по адресу WININET!DispatchAPICall+0x3f которая вызывается между сохранением/восстановлением MMX регистров вы смотрели? Ну и к выравниванию стека это вообще отношения не имеет.
кт>По-моему мы друг друга не понимаем. Какие "дебажные символы" отобразятся в командах запоминания? Я в Windbg всего лишь прошел пошагово несколько десятков команд внутри вызова InternetGetConnectedState и обнаружил запоминание/восстановление XMM, хотя по смыслу эта функция всего лишь должна достать внутренний флаг. Запоминание ненужных в данном случае регистров потребовало выравнивания стека на 16, а если бы не было ненужных XMM, достаточно обычного выравнивания на 8.
Деюажные символы, которые бы помогли понять что за код находится по WININET!DispatchAPICall+0x3f0, возможно это навело бы вас на мысль что InternetGetConnectedState далеко не так проста как кажется. К примеру на моей системе InternetGetConnectedState просто вызывает InternetGetConnectedStateEx, а та внутри дохрениша чего делает, включая вызов колбэков и обращение по RPC к системным сервисам.


O>>В вашем примере компилятор решил сохранить SSE перед вызовом непубличной функции. Это его право, так как для непубличных функций компилятор вправе положить на volatile/preserved registers.

кт>Да пусть себе что хочет делает внутри. А снаружи вызова InternetGetConnectedState зачем знать какие функции он ВНУТРИ вызывает. Если внутри есть экзотические вызовы, пусть внутри и разбирается с дополнительными требованиями. А то так перед ЛЮБЫМ вызовом придется все сохранять и выравнивать. Это потеря времени и увеличение размера кода.
Вот этот код который вы привели, это как я полагаю и есть код InternetGetConnectedState? А значит он и есть ВНУТРИ InternetGetConnectedState. Почему вас смущает что InternetGetConnectedState сохраняет внутри себя MMX регистры перед тем как вызывать какие то свои внутренние потроха (которые юзают SSE)?


OO>>Еще раз: есть пример кода, когда конкретно этот сценарий использования исключений работает некорректно на х64? Или ваши жалобы касаются лишь того что сложно все это понять "на глазок" как оно все теперь работает и быстро на коленке обработать это дело самописным дебаггером?

кт>И опять мы друг друга не поняли. Причем здесь стек? Пример опровергал утверждение
кт>"Работоспособность программы после какого нить illegal instruction или поломанной памяти на самом деле никому не интересна".
Действительно не понимаем. Я имел ввиду что есть два рода исключений. Первое — исключения уровня логики приложения. Второе — исключения уровня защиты ОС от неверного функционирования программы. Ваше underflow exception — относится к первым. Такие не могут привести к вызову обработчика исключений на невыровненном стеке, поскольку места из которых они могут вылететь известны компилятору и он генерит код таким образом, чтобы исключения логики генерились на корректном стеке.
Если же исключение возникает изза жесткой ошибки защиты — изза неверно выделенной памяти или изза того что после расстрела стека исполнение пошло по мусорному коду, это означает что исполнение программы дальше невозможно. Баста, остается только позвать по LPC post-mortem дебаггер.

кт>На мой взгляд, ОС должна передать исключение обработчику, а дальше не ее собачье дело "интересно" это кому-нибудь или "неинтересно". Автор статьи ругается, что исключение есть, обработчик на него есть, а ОС его не вызывает, потому, что дескать стек обязательно должен был быть кратен 8. Ну не кратен 8, аппаратно ведь запрещения на это нет? ОС-то зачем это запрещает?

Потому что есть соглашения об адекватном валидном коде, которые несколько выше чем "аппаратно". И согласно которым стек должен всегда оставаться выровненным на 8 (а при вызове публичной функции, в ее прологе — на 16). Если он таковым вдруг не стал — значит код не валидный. Мнения любителей писать выверты на асме прошло. Теперь балом правит кодогенератор.
Это чисто измышления автора. Я лично понимаю разработчиков ОС. Факт того что стек оказался не выравнен на 8 указывает на то что исключене является фатальным, потому что в корректном коде такого произойти не должно. А значит лучше всего ничего не делать на этом стеке чтобы не наломать еще больших дров.
Re[7]: особенности структурной обработки исключений в Win64
O>>Дебажные символы. windbg настраивается на публичный микрософтовский символ-сервер двумя командами: .symfix и .reload
O>>С чего вы взяли что сохранение бездумное, а функция простейшая? Что за код по адресу WININET!DispatchAPICall+0x3f которая вызывается между сохранением/восстановлением MMX регистров вы смотрели? Ну и к выравниванию стека это вообще отношения не имеет.
кт>По-моему мы друг друга не понимаем. Какие "дебажные символы" отобразятся в командах запоминания? Я в Windbg всего лишь прошел пошагово несколько десятков команд внутри вызова InternetGetConnectedState и обнаружил запоминание/восстановление XMM, хотя по смыслу эта функция всего лишь должна достать внутренний флаг. Запоминание ненужных в данном случае регистров потребовало выравнивания стека на 16, а если бы не было ненужных XMM, достаточно обычного выравнивания на 8.
Деюажные символы, которые бы помогли понять что за код находится по WININET!DispatchAPICall+0x3f0, возможно это навело бы вас на мысль что InternetGetConnectedState далеко не так проста как кажется. К примеру на моей системе InternetGetConnectedState просто вызывает InternetGetConnectedStateEx, а та внутри дохрениша чего делает, включая вызов колбэков и обращение по RPC к системным сервисам.


O>>В вашем примере компилятор решил сохранить SSE перед вызовом непубличной функции. Это его право, так как для непубличных функций компилятор вправе положить на volatile/preserved registers.

кт>Да пусть себе что хочет делает внутри. А снаружи вызова InternetGetConnectedState зачем знать какие функции он ВНУТРИ вызывает. Если внутри есть экзотические вызовы, пусть внутри и разбирается с дополнительными требованиями. А то так перед ЛЮБЫМ вызовом придется все сохранять и выравнивать. Это потеря времени и увеличение размера кода.
Вот этот код который вы привели, это как я полагаю и есть код InternetGetConnectedState? А значит он и есть ВНУТРИ InternetGetConnectedState. Почему вас смущает что InternetGetConnectedState сохраняет внутри себя MMX регистры перед тем как вызывать какие то свои внутренние потроха (которые юзают SSE)?


OO>>Еще раз: есть пример кода, когда конкретно этот сценарий использования исключений работает некорректно на х64? Или ваши жалобы касаются лишь того что сложно все это понять "на глазок" как оно все теперь работает и быстро на коленке обработать это дело самописным дебаггером?

кт>И опять мы друг друга не поняли. Причем здесь стек? Пример опровергал утверждение
кт>"Работоспособность программы после какого нить illegal instruction или поломанной памяти на самом деле никому не интересна".
Действительно не понимаем. Я имел ввиду что есть два рода исключений. Первое — исключения уровня логики приложения. Второе — исключения уровня защиты ОС от неверного функционирования программы. Ваше underflow exception — относится к первым. Такие не могут привести к вызову обработчика исключений на невыровненном стеке, поскольку места из которых они могут вылететь известны компилятору и он генерит код таким образом, чтобы исключения логики генерились на корректном стеке.
Если же исключение возникает изза жесткой ошибки защиты — изза неверно выделенной памяти или изза того что после расстрела стека исполнение пошло по мусорному коду, это означает что исполнение программы дальше невозможно. Баста, остается только позвать по LPC post-mortem дебаггер.

кт>На мой взгляд, ОС должна передать исключение обработчику, а дальше не ее собачье дело "интересно" это кому-нибудь или "неинтересно". Автор статьи ругается, что исключение есть, обработчик на него есть, а ОС его не вызывает, потому, что дескать стек обязательно должен был быть кратен 8. Ну не кратен 8, аппаратно ведь запрещения на это нет? ОС-то зачем это запрещает?

Потому что есть соглашения об адекватном валидном коде, которые несколько выше чем "аппаратно". И согласно которым стек должен всегда оставаться выровненным на 8 (а при вызове публичной функции, в ее прологе — на 16). Если он таковым вдруг не стал — значит код не валидный. Время любителей писать выверты на асме прошло. Теперь балом правит кодогенератор.
Это чисто измышления автора. Я лично понимаю разработчиков ОС. Факт того что стек оказался не выравнен на 8 указывает на то что исключене является фатальным, потому что в корректном коде такого произойти не должно. А значит лучше всего ничего не делать на этом стеке чтобы не наломать еще больших дров.