Как работает «раскрутчик» стека в x64
Oct 27, 2008 · Commentsamd64Обработка исключенийПрограммирование
В комментариях к предыдущем посте про исключения верно заметили, что exception chain в TEB используется только в x86 коде. И x64, и ia64 exception chain не используют вообще. Как же, в таком случае, выполняется «раскрутка» стека при обработке исключения?
Когда создавалась архитектура x64, её создатели не хотели повторять ошибки прошлого и наступать на те же грабли, на которые наступили их предшественники. В частности для x64 существует стандарт соглашения о вызовах, который регламентирует:
-
Точный формат кадра стека (stack frame);
Чем это лучше того, что твориться в мире x86 кода? Стандартный формат кадра стека позволяет получать достоверную трассировку стека в любой момент времени, при условии, конечно, что компилятор генерирует код соответствующий соглашению о вызовах и если информация о состоянии процессора корректна. При этом абсолютно не используются символы (.pdb). Сравните это с x86, где совершенно корректный код может запросто свести с ума любой отладчик.
Далее, все функции делятся на два типа: «frame» и «leaf». К первым относится любая функция вызывающая другие функции, сохраняющая nonvolatile регистры или использующая исключения. Функции, динамически выделяющие память в стеке с помощью _alloca, также относятся к этой категории. Все остальные – это «leaf» функции. Для каждой «frame» функции компилятор генерирует её описание (function entry), где подробно описываются все действия, выполняемые в прологе функции: от выделения места в стеке до списка сохраняемых регистров вместе с их смещениями в стеке. Пример можно посмотреть, выполнив в отладчике команду “.fnent ”:
0:000> .fnent notepad!WinMain
Debugger function entry 00000000`01f48250 for:
(00000000`ff296dd4) notepad!WinMain | (00000000`ff296fd0) notepad!UpdateStatusBar
Exact matches:
notepad!WinMain = <no type information>
BeginAddress = 00000000`00006dd4
EndAddress = 00000000`00006fc9
UnwindInfoAddress = 00000000`0000dcc0
Unwind info at 00000000`ff29dcc0, 14 bytes
version 1, flags 0, prolog 14, codes 8
frame reg 0, frame offs 0
00: offs 14, unwind op 4, op info 6
01: offs 12, unwind op 0, op info 0
02: offs 14, unwind op 4, op info 5
03: offs 11, unwind op 0, op info 0
04: offs 14, unwind op 4, op info 3
05: offs 10, unwind op 0, op info 0
06: offs 14, unwind op 2, op info d
07: offs 10, unwind op 0, op info 7
Более подробно об этом можно почитать здесь. Имея подобное описание «раскрутчик» стека может достоверно определить границы кадров функций в стеке и восстановить значение non-volatile регистров в каждом кадре в любой момент времени.