Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET functions disassembled

When disassembling .NET functions, I notice that they all start with a similair pattern. What does this initial code do?

This code appear before the actual code for what the function is supposed to do. Is it some sort of parameter count verification?

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  

[Edit] So is this a correct description of it?

//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  

or?

like image 757
Roger Johansson Avatar asked Feb 10 '11 13:02

Roger Johansson


1 Answers

This prologue has two parts.

Setting up the stackframe

This stores the current EBP register on the stack and then assigns the value of the stackpointer(ESP) to EBP.

push        ebp  mov         ebp,esp 

If there are local variables that are stored on the stack (i.e. not enough space in the registers available) then ESP will be moved by their size to build the stackframe of the current function.

And at the end of the function you'll see these operations reversed, so the stack-frame of the previous function gets restored.

EBP should always point to the beginning of the stackframe of the current function
ESP to the end(which has a lower address on x86 because the stack grows downwards).

This is part of the common calling conventions and needed for stack unrolling when an exception is thrown. This is not .net specific and used by most calling conventions on windows/x86.

After setting up the stackframe its common to store some registers on the stack. That's because you might want to use certain registers as temporary variables, but the calling convention requires your function to conserve them. So you need to back them up on the stack. Which registers must be preserved and which can be modified depends on the calling convention you use.

When referring to local variables on the stack you can use [ebp-x] where ebp points to the beginning of the stackframe, and x is an offset which indicates where in the stackframe the variable is stored. Alternatively you can use [esp+y] with an offset from the end of the stackframe.

Call to the static constructor/initializer

As danbystrom noticed the second part is most likely the call to a static constructor/initializer. Since the static constructor is not called on program startup but on the first access, every access for which the jitter can't guarantee that the static constructor has already executed needs to check if it has been called, and then calls it if not.

00000004  cmp         dword ptr ds:[006914A4h],0  0000000b  je          00000012  0000000d  call        65CC36CF 

This is something like if (globalVar!=0) Call Function_65CC36CF. Where most likely the global var indicates if the static constructor has run, and the call is a call to the static constructor.


As far as I know your comments on the disassembly are correct.


Check this OldNewThing blog entry on stackframes: How to rescue a broken stack trace: Recovering the EBP chain

like image 62
CodesInChaos Avatar answered Oct 08 '22 15:10

CodesInChaos