Как работает «раскрутчик» стека в x64

В комментариях к предыдущем посте про исключения верно заметили, что exception chain в TEB используется только в x86 коде. И x64, и ia64 exception chain не используют вообще. Как же, в таком случае, выполняется «раскрутка» стека при обработке исключения?

Когда создавалась архитектура x64, её создатели не хотели повторять ошибки прошлого и наступать на те же грабли, на которые наступили их предшественники. В частности для x64 существует стандарт соглашения о вызовах, который регламентирует:

Чем это лучше того, что твориться в мире 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 регистров в каждом кадре в любой момент времени.

comments powered by Disqus