А что, собственно, происходит, когда бросается исключение?
Нет, ну в общих чертах понятно – процессор генерирует исключение, операционная система находит нужный обработчик и вызывает его. А что происходит, если посмотреть подробнее? В Windows происходит примерно следующее.
Выполняя поток команд, процессор проверят возможность выполнения каждой инструкции, корректность её аргументов и все остальные факторы, влияющие на корректность выполнения кода. В случае если команда не может быть выполнена (деление на ноль, обращение к несуществующей странице, несоответствие уровня привилегий и т.д.), процессор генерирует исключение – вызывает один из обработчиков, зарегистрированных операционной системой в IDT (Interrupt Dispatch Table).
При вызове обработчика процессор делает сразу несколько вещей: переключается в режим ядра (Ring 0), переключает указатель стека на ядерный стек и сохраняет предыдущие указатели команд и стека в ядерном стеке.

Получив контроль, обработчик исключения сохраняет остальные регистры процессора в стеке и выполняет действия, специфичные для конкретного исключения. Например, обработчик Page Fault Exception запрашивает подкачку страницы у Memory Manager. Если обработчику удалось разрешить проблему, вызвавшую генерацию исключения, обработчик восстанавливает сохраненное состояние процессора и выполняет возврат в пользовательский код (Ring 3). В противном случае, в дело вступает диспетчер исключений.
Диспетчер исключений размещает структуру CONTEXT в пользовательском стеке и копирует туда сохранённое состояние регистров из ядерного стека. Туда же сохраняется текущее состояние Floating Point регистров. Информация об исключении записывается в структуру EXCEPTION_RECORD. Далее, диспетчер подменяет адрес возврата в пользовательский код адресом диспетчера исключений пользовательского режима и выполняет возврат в Ring 3.
Windows поддерживает специальную структуру, TEB (Thread Environment Block), где хранятся локальные данные потока. Эта структура доступна из Ring 3 через сегмент FS (или GS для x64). В самом начале этой структуры хранится указатель на список вложенных блоков “__try” и соответствующих им блоков “__except” и “__finally”. Компилятор генерирует код, добавляющий элемент в этот список при входе в блок “__try” и удаляющий при выходе из блока. (Примечание: справедливо только для x86. 64-х битный код “раскручивает” стек пользуясь сгенерированным компилятором описанием кода.)

Получив управление, диспетчер исключений пользовательского режима по очереди опрашивает обработчики из списка, позволяя каждому из них обработать данное исключение. Найдя обработчик, согласившийся обработать исключение, диспетчер исключений выполняет «раскрутку» стека (Stack Unwinding) и передает управление выбранному обработчику. Этот механизм довольно детально описывался во всевозможных статьях о том, как работает SEH (Structured Exception Handling) (например здесь или здесь), так что я не буду останавливаться на этом детально. «Раскрутчик» стека отслеживает текущее состояние (указатель стека и команд, состояние регистров) в локальной копии структуры CONTEXT. По окончанию обработки исключения, состояние из структуры CONTEXT загружается в процессор, завершая обработку исключения.
И это только поверхностное описание.
помню еще в режиме рального времени (под ДОС) в самом начале памяти (с адреса 0) лежала таблица адресов обработчиков прерываний (от таймера, клавы, … ). насколько помню там же был обработчик исключений (хотя могу путать).
Interrupt Dispatch Table – это та (старая добрая) таблица и есть?
Она самая, только в защищенном режиме у неё формат совсем другой и располагаться она может где угодно в памяти.
> В самом начале этой структуры хранится указатель на список вложенных блоков “__try” и соответствующих им блоков “__except” и “__finally”.
Это справедливо для х86, в х64 таблицы “фреймов” статические. Или же TIB::ExceptionList остался в х64 для поддержки wow64?
Не, это я нахомутал. На картинках – x64 регистры, а описание exception chain – для x86. Познее напишу небольшой пост про отличия x64 от x86 и каким боком там Wow64 приделана. Вот здесь вот есть совсем подробное описание как делается unwinding на x64: http://www.nynaeve.net/?p=113
PS: TIB::ExceptionList есть и в 64-х битном TEB, но указывает он совсем не на exception chain.
А на что он указывает, если не секрет?
Ну это же так просто.
Сначала:
windbg.exe notepad.exe
!teb
А затем:
windbg.exe %windir%\syswow64\notepad.exe
!teb
ExceptionList 64-х битного TEB указывает на 32-х битный TEB, если он есть.
А в чем нарисованы столь красивые картинки?
PowerPoint
Ага, картинки и в самом деле хороши.
Текст, врочем, тоже.
Злостный офтопик (не путать со спамом!):
А ты не мог бы прояснить ситуацию: как там дела в Микрософте? Вон на привете пишут, что “hiring frozen”, потом ссылки дают, что таки не фрозен.
Есть смысл вам в контору CV отсылать, или стоит подождать пару месяцев, пока все не устоканится?
Сложно сказать. Hiring freeze как таковой ещё не случился, по моим сведениям. По крйней мере продолжают нанимать. Но слухи ходят скорее всего неспроста. Я бы ожидал, что активность набора активность набора должна была бы снизтся. Кризис, все дела. Как на самом деле – хз.
Тут еще длительность процесса найма ограет роль. Те кто приходит сейчас прошли интервью и были наняты более месяца назад на самом деле. Т.е. до обвального падения индексов и легкой паники в сочетании с чуством легкой поживы…
P.S. Смысл отсылать резюме есть всегда. Даже когда точно не нанимают. Оно кушать не просит.