I'm a bit rusty with this, but I'm also interested in the low level assembly side of things. Here goes:
push ebp; save stack frame pointer
Push the value stored in EBP onto the stack, so that when we return from this method, we know where we came from.
mov ebp,esp; setup current frame
Move current stack position value from ESP to EBP, so that EBP is in the context of the current method.
The preceding two lines of code are a convention that ensures there's a fixed position (stored in the EBP register) on the stack determining relative location of local variables.
call 6F03BE38; Console.Out property getter
No prizes for guessing that this is a call to Console.Out
mov ecx,eax; setup "this"
Returned values from methods are stored in EAX, which is a matter of the calling convention. Thus the returned value from Console.Out
will be stored in EAX. Here, that value is copied to ECX for later use, making EAX usable for other purposes.
mov edx,dword ptr ds:[02BD2088h]; arg = "Hello world"
The register EDX is given the memory location of the string "Hello World". dword ptr ds:[02BD2088h]
means dereferences the memory location ds:[02BD2088h]
, where ds
is the data segment (where things like initialised strings are stored). [02BD2088h]
is an offset in the memory region of ds
.
mov eax,dword ptr [ecx]; TextWriter reference
Remember that Console.Out
call? We put the returned value from that into ECX. Here, the memory address of ECX is dereferenced, so that the memory address of the TextWriter is copied into EAX. So EAX will now contain the actual memory address of the TextWriter object. If we did mov eax,dword ptr ecx;
then EAX would contain the pointer to the memory address of the TextWriter, not the actual memory address of TextWriter. (I still get confused with that myself).
call dword ptr [eax+000000D8h]; TextWriter.WriteLine()
Here a call is made to TextWriter.WriteLine()
. I'm assuming that TextWriter.WriteLine()
is using the _fastcall
calling convention (a good explanation of calling conventions can be found here) which means it uses the EDX register to find arguments passed to the method.
pop ebp; restore stack frame pointer
We remove the top-most (or bottom-most really, as stacks actually grow downwards) value into EBP, so the frame pointer in EBP now corresponds to the calling method.
ret
Return to the location found at the top of the stack, back into the calling method. In this case, as it's Main()
being called, control will be returned to system code and the application will exit.