.NET функции разобраны - PullRequest
       13

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

31 голосов
/ 10 февраля 2011

При разборке функций .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 

или?

Ответы [ 3 ]

19 голосов
/ 10 февраля 2011

Этот пролог состоит из двух частей.

Настройка стекового кадра

Сохраняет текущий регистр EBP в стеке, а затем присваивает значение указателя стека (ESP) для EBP.

push        ebp 
mov         ebp,esp

Если в стеке хранятся локальные переменные (т. Е. Недостаточно места в доступных регистрах), ESP будет перемещен на их размер для построения стекового кадра текущей функции.

И в конце функции вы увидите, что эти операции перевернуты, поэтому стековый фрейм предыдущей функции восстанавливается.

EBP всегда должен указывать на начало стекового фрейма текущей функции
ESP до конца (который имеет меньший адрес на x86, потому что стек растет вниз).

Это часть общих соглашений о вызовах, необходимая для развертывания стека при возникновении исключения. Это не специфично для .net и используется большинством соглашений о вызовах в windows / x86.

После настройки стекового кадра принято хранить некоторые регистры в стеке. Это потому, что вы можете использовать определенные регистры в качестве временных переменных, но соглашение о вызовах требует от вашей функции их сохранения. Таким образом, вы должны сохранить их в стеке. Какие регистры должны быть сохранены, а какие могут быть изменены, зависит от используемого соглашения о вызовах.

При обращении к локальным переменным в стеке вы можете использовать [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. Где, скорее всего, глобальная переменная указывает, был ли запущен статический конструктор, а вызов - это вызов статического конструктора.


Насколько я знаю, ваши комментарии по разборке верны.


Проверьте эту запись блога OldNewThing на стековых фреймах: Как восстановить поврежденную трассировку стека: восстановление цепочки EBP

2 голосов
/ 10 февраля 2011

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

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's code
0 голосов
/ 10 февраля 2011

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

...