Ответ 1
Этот пролог состоит из двух частей.
Настройка стекового кадра
Здесь хранится текущий регистр EBP в стеке, а затем присваивается значение счетчика стека (ESP) для EBP.
push ebp
mov ebp,esp
Если есть локальные переменные, которые хранятся в стеке (т.е. недостаточно места в доступных регистрах), то ESP будет перемещаться по их размеру для создания стекового кадра текущей функции.
И в конце функции вы увидите, что эти операции отменены, поэтому восстанавливается стоп-кадр предыдущей функции.
EBP всегда должен указывать на начало стекового кадра текущей функции
ESP до конца (который имеет более низкий адрес на x86, потому что стек растет вниз).
Это часть общих соглашений вызова и требуется для разворачивания стека при вызове исключения. Это не является специфичным для сети и используется большинством вызовов на окнах /x 86.
После настройки стекового фрейма его общий для хранения некоторых регистров в стеке. Это потому, что вы можете использовать определенные регистры в качестве временных переменных, но для вызывающего соглашения требуется, чтобы ваша функция сохраняла их. Поэтому вам нужно создать резервную копию в стеке. Какие регистры должны быть сохранены и которые могут быть изменены, зависит от используемого вами соглашения о вызовах.
При обращении к локальным переменным в стеке вы можете использовать [ebp-x]
, где ebp
указывает на начало стекового кадра, а x - смещение, которое указывает, где в стеке кадр хранится переменная. В качестве альтернативы вы можете использовать [esp+y]
со смещением от конца стекового кадра.
Вызов статического конструктора/инициализатора
Как danbystrom заметила, что вторая часть, скорее всего, является вызовом статического конструктора/инициализатора. Поскольку статический конструктор не вызывается при запуске программы, но при первом доступе каждый доступ, для которого джиттер не может гарантировать, что статический конструктор уже выполнил, должен проверить, был ли он вызван, а затем вызывает его, если нет.
00000004 cmp dword ptr ds:[006914A4h],0
0000000b je 00000012
0000000d call 65CC36CF
Это что-то вроде if (globalVar!=0) Call Function_65CC36CF
. Где, скорее всего, глобальный var указывает, запущен ли статический конструктор, а вызов - это вызов статического конструктора.
Насколько я знаю, ваши комментарии к разборке верны.
Отметьте эту запись в блоге OldNewThing на стековых кадрах: Как спасти сломанную трассировку стека: Восстановление цепи EBP