Sign In
MSDN Blogs
Microsoft Blog Images
More ...
A tryst with MSIL
Recent Posts
Video – Configuring DebugDiag for process crash
Posted
over 2 years ago
by
Shinva
0
Comments
Fingerprinting IIS
Posted
over 2 years ago
by
Shinva
0
Comments
MIB OIDs for IIS 6.0
Posted
over 2 years ago
by
Shinva
1
Comments
64 bit IIS manager,32 bit worker process and root web.config settings
Posted
over 3 years ago
by
Shinva
0
Comments
ASP.NET Debugger Extension – Manual Install / Uninstall
Posted
over 3 years ago
by
Shinva
0
Comments
Tags
.NET
ASP.NET
C#
Debug
IIS
IIS 7 Tip
InternetExplorer
Live
PowerShell
SCCM
Security
SSRS
Tools
VisualStudio
WinDbg
Windows
Archives
Archives
September 2010
(2)
January 2010
(1)
December 2009
(1)
November 2009
(5)
October 2009
(1)
September 2009
(2)
August 2009
(1)
July 2009
(1)
May 2009
(5)
April 2009
(4)
March 2009
(5)
February 2009
(4)
January 2009
(3)
November 2008
(1)
October 2008
(2)
September 2008
(1)
May 2008
(3)
April 2008
(3)
March 2008
(3)
February 2008
(2)
January 2008
(2)
December 2007
(3)
November 2007
(3)
October 2007
(2)
May 2007
(1)
November 2006
(2)
Common Tasks
Blog Home
Email Blog Author
About
RSS for comments
RSS for posts
MSDN Blogs
>
The Way I See It
>
A tryst with MSIL
A tryst with MSIL
Shinva
30 Nov 2006 12:59 AM
Comments
0
Any ASP.NET developer should be knowing that when his/her .NET application is compiled, the high-level code written in C# or Visual Basic .NET is compiled into the intermediate language MSIL. It is this MSIL that the Common Language Runtime (CLR) actually expects when the application is run. The CLR then converts the MSIL into platform-specific code (Just-In-Time compilation) while running the application.
MSIL (MicroSoft Intermediate Language) as the name suggests is a language in itself, so why not actually code your application directly using MSIL instead of using any high-level language like C# or VB.NET. Of course it is not an easy task, think of it as an abstract high-level assembly language.
This article will give you an insight into coding using MSIL. I seriously don't think anyone will abandon the pleasures of C# or VB.NET and start coding in MSIL. But at least the next time you ILDASM a .NET exe or dll you will know what you are looking at.
Coding in MSIL revolves around the stack (would sound familiar if you know assembly language). Basically any parameters that you need to pass to a function or any operands for an command have to first populated on to the stack. After the command or function is executed it reads the required data from the stack and the result is stored onto the stack again.
In short
1. Push the operands / parameters on to the stack
2. Execute the command / function
3. Pop the result from the stack
So let's start with the most famous program in computer history... Hello World!
.assembly HelloWorld {}
.method static void HelloWorld()
{
.entrypoint
.maxstack 1
ldstr "Hello World!"
call void [mscorlib]System.Console::WriteLine(string)
ret
}
The first thing a C, C++ or even a C# coder would question is Where is main() ? Well in MSIL the program entry point is not restircted to the main() function. Here you can define any method as the entry point by just specifying the directive
.entrypoint
. So now any method that has the .
entrypoint
directive will be your main(). Only one method in the application can have this directive.
Now this piece of code prints out Hello World! on the console. It achieves this by calling the WriteLine method. As discussed earlier before a method call any parameter that has to be passed to it has to be pushed onto the stack. Here we need to push one parameter and that is the maximum stack space we are going to use. The next line of code
.maxstack
1 indicates the max number of stack slots the method will use. In our case it is just one.
The next instruction
ldstr
pushes the string that we need to print onto the stack. The call instruction then invokes the WriteLine() method that prints out the string. There is a significant difference between IL and other programming languages when it comes to calling a function. In IL, when we are calling a function, we have to completely specify a function, including its namespace, return type and data type of its parameter
call
<return type> <namespace>.<class name>::<function name>(parameter type)
The last statement
ret
as you must have guessed returns execution to the caller.
To convert this piece of code into an executable use the ILASM.EXE(Shipped with the framework).
Now lets complicate things a little. We will try writing this C# code in MSIL
public static void Main()
{
int a, b, c;
a = Convert.ToInt32(Console.ReadLine());
b = Convert.ToInt32(Console.ReadLine());
try
{
c = a / b;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Here is the corresponding MSIL code
.method public static void division()
{
.entrypoint
.maxstack 2
.locals init (int32,
int32,
int32,
class [mscorlib]System.Exception)
call string [mscorlib]System.Console::ReadLine()
call int32 [mscorlib]System.Convert::ToInt32(string)
stloc.0
call string [mscorlib]System.Console::ReadLine()
call int32 [mscorlib]System.Convert::ToInt32(string)
stloc.1
.try
{
ldloc.0
ldloc.1
div
stloc.2
ldloc.2
call void [mscorlib]System.Console::WriteLine(int32)
leave.s CONTINUE
}
catch [mscorlib]System.Exception
{
stloc.3
ldloc.3
callvirt instance string [mscorlib]System.Exception::get_Message()
call void [mscorlib]System.Console::WriteLine(string)
leave.s CONTINUE
}
CONTINUE:
ret
}
Something that immediately stands out in this piece of code is the
.locals
directive. Yes it is used to declare local variables. So I am declaring three int32 variables for a,b and c and one object for ex for the exception handling. You should have noticed that the variables are not named(like a,b and c). This is because you can refer to the variables by their index just like an array. You can also use identifiers for variables and define them as .locals init(int32 a, and then refer to the variables using the identifiers.
Now again handling local variables also revolves round the stack. To push a local variable value onto the stack use the
ldloc
instruction. And to pop a value off the stack and populate a local variable use the
stloc
instruction.
So now this is how the code translates
int a, b, c;
.locals init (int32, int32, int32)
a = Convert.ToInt32(Console.ReadLine());
call string [mscorlib]System.Console::ReadLine()
call int32 [mscorlib]System.Convert::ToInt32(string)
stloc.0
c = a / b;
ldloc.0
ldloc.1
div
stloc.2
Exception handling as you see looks similar to C# but for one small difference
leave.s
this is a jump instruction to transfer control(remember the goto statement)
By now you must have understood that coding in MSIL is all about breaking down expressions and statements into simple instructions that can be executed in sequence. Let us look at how the
if
statement can be implemented.
if (a == b)
{
/*Statements when true
}
/*Statements
ldloc.0
ldloc.1
ceq
ldc.i4.0
ceq
brtrue.s CONTINUE
/*Statements when true
CONTINUE:
/*Statements
The
ceq
instruction pops off two values from the stack, compares them, and then pushes 1 onto the stack if they are equal or 0 if not. The
brtrue.s
instruction handles the conditional branching, it transfers control to the given target if the value on the stack is non-zero. That is the reason we actually compare the result of the first ceq again with a temporary value of zero(i4). If you want to skip the second comparision you can use the
brfalse.s
which branches off when the value on the stack is zero.
And if you are thinking about the
for
statement it gets even dirtier. In short a
for
statement can be implemented as follows
Initialize Index
Jump To CONDITION
LOOP:
Increment Index
CONDITION:
If Index not equals N
Jump to LOOP
You have to implement the
if
statement as discussed above and for the unconditional jumps you can use the
br.s
instruction.
To bring everything together, MSIL is all about breaking down expressions and statements into simple instructions that can be executed in sequence. The code may seem overly complicated, but knowing how things work at the lowest level does make it easier to see the big picture.
0 Comments
ASP.NET
,
.NET
,
C#
Leave a Comment
Name
Comment
Please add 2 and 2 and type the answer here:
Post