Подтвердить что ты не робот

Функции .NET разобраны

При разборке функций .NET я замечаю, что все они начинаются с шаблона similair. Что делает этот исходный код?

Этот код появляется перед фактическим кодом для функции, которую должна выполнять функция. Это какая-то проверка счетчика параметров?

func1

private static void Foo(int i)
{
   Console.WriteLine("hello");
}

00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  push        eax 
00000004  mov         dword ptr [ebp-4],ecx 
00000007  cmp         dword ptr ds:[005C14A4h],0 
0000000e  je          00000015 
00000010  call        65E0367F 
//the console writleline code follows here and is not part of the question

func2

static private void Bar()
{
   for (int i = 0; i < 1000; i++)
   {
      Foo(i);
   }
}

00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  push        eax 
00000004  cmp         dword ptr ds:[006914A4h],0 
0000000b  je          00000012 
0000000d  call        65CC36CF 
// the for loop code follows here

FUNC3

private static void Foo()
{
   Console.WriteLine("hello");
}

00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  cmp         dword ptr ds:[005614A4h],0 
0000000a  je          00000011 
0000000c  call        65E3367F 

[Изменить] Так это правильное описание?

//fix stackframe
00000000  push        ebp 
00000001  mov         ebp,esp 
//store eax so it can be used locally
00000003  push        eax 
//ensure static ctor have been called
00000004  cmp         dword ptr ds:[006914A4h],0 
//it has been called, ignore it
0000000b  je          00000012
//it hasn't been called, call it now 
0000000d  call        65CC36CF 

или

4b9b3361

Ответ 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

Ответ 2

Поскольку ваши методы все статичны: код используется для проверки того, был ли еще запущен статический инициализатор класса.

00000007  cmp    dword ptr ds:[005C14A4h],0  ; test if static initializer has executed
0000000e  je     00000015                    ; skip call to initializer if already done
00000010  call   65E0367F                    ; call static initializer
00000015  ....                               ; continue with the method code

Ответ 3

Если вы говорите о push и mov, он просто фиксирует столбец. Я не уверен, что остальная часть этих сегментов работает с моей головы.