在反汇编.NET函数时,我注意到它们都是以类似的模式开始的。 这个初始代码做了什么?
此代码出现在函数应该执行的实际代码之前。 它是某种参数计数验证吗?
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
或
答案 0 :(得分:19)
本序言分为两部分。
这会将当前EBP寄存器存储在堆栈中,然后将堆栈指针(ESP)的值分配给EBP。
push ebp
mov ebp,esp
如果堆栈中存在局部变量(即寄存器中没有足够的空间可用),那么ESP将按其大小移动以构建当前函数的堆栈帧。
在函数结束时,您将看到这些操作相反,因此前一个函数的堆栈帧将被恢复。
EBP应始终指向当前函数
的堆栈帧的开头
ESP到最后(在x86上的地址较低,因为堆栈向下增长)。
这是常见调用约定的一部分,在抛出异常时需要进行堆栈展开。这不是.net特定的,并且被大多数调用约定用于windows / x86。
设置堆栈帧后,它常用于在堆栈中存储一些寄存器。那是因为您可能希望将某些寄存器用作临时变量,但调用约定需要您的函数来保存它们。所以你需要将它们备份到堆栈中。哪些寄存器必须保留,哪些可以修改取决于您使用的调用约定。
当引用堆栈上的局部变量时,可以使用[ebp-x]
,其中ebp
指向堆栈帧的开头,x是一个偏移量,表示存储变量的堆栈帧中的位置。或者,您可以使用[esp+y]
与堆栈帧末尾的偏移量。
由于danbystrom注意到第二部分很可能是对静态构造函数/初始化程序的调用。由于静态构造函数不是在程序启动时调用,而是在第一次访问时调用,因此抖动无法保证静态构造函数已经执行的每次访问都需要检查它是否已被调用,然后如果没有则调用它。 / p>
00000004 cmp dword ptr ds:[006914A4h],0
0000000b je 00000012
0000000d call 65CC36CF
这就像if (globalVar!=0) Call Function_65CC36CF
。最可能全局变量指示静态构造函数是否已运行,并且该调用是对静态构造函数的调用。
据我所知,您对反汇编的评论是正确的。
在stackframes上查看此OldNewThing博客条目:How to rescue a broken stack trace: Recovering the EBP chain
答案 1 :(得分: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's code
答案 2 :(得分:0)
如果你正在谈论push和mov,它只是修复了callstack。我不确定这些细分市场的其余部分是什么作用。