|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionThis article teaches the basics of IL Assembly language which can be used to debug your .NET code (written in any .NET high level language) at low level. From low level, I meant the point where the compiler of your high level language has finished his work. Also, using these basics, you can plan to write your own compiler for a new .NET language. Table of contents
Whenever you complier your code in .NET, regardless the language you choose, it is converted to Intermediate Language (IL) which is also known as Microsoft Intermediate Language or Common Intermediate Language. You can think the IL as that the Byte Code generated by the Java Language. If you are interested to understand that how .NET deals with data types, and how the code you wrote is converted to IL code etc, then knowledge of IL will give you great advantages. These advantages may include understanding that what the code .NET compiler emits. Hence, if you know the IL, then you can examine the code emitted by the complier and make necessary changes (though not needed in most cases). You can change the IL code to make necessary changes (which your high level language may not allow) to increase the performance of you code. This also may help you to debug your code at low level. And also, if you are planning to write a compiler for .NET, then it is necessary to understand the IL. IL itself is in the binary format which means it can't be read by the human. But as other binary (executable) code have an assembly language, so the same way IL also has an assembly language known as IL Assembly (ILAsm). IL Assembly has the instruction in the same way as that the native assembly language have. Like, to add two numbers, you have add instruction, to subtract two numbers, you have sub instruction etc. It is obvious that .NET runtime (JIT) can not execute the ILAsm directly. If you have written some code in ILAsm then first you have to compile that to IL code and then JIT will take care of running this IL code. NOTE: Please note that IL and IL assembly are two different things. Whenever we talk about IL, then it means the binary code emitted by the .NET compiler whereas ILAsm will refer to the IL assembly language which is not in binary form. NOTE: Please note that I am expecting that you are very much familiar with .NET (including any high level language). In this article, I will not go into details of everything but only those which I think are needed to be explained. If something confuse you, then you can contact me for more discussion. Introduction to IL Assembly LanguageNow let's start the main purpose of this article, the introduction to IL Assembly. ILAsm has the instruction set same as that the native assembly language has. You can write code for ILAsm in any text editor like notepad and then can use the command line compiler (ILAsm.exe) provided by the .NET framework to compile that. ILAsm is a tough job for those programmers who have been working in high level languages only but the programmers of C or C++ may adopt it easily. It it’s a tough job then we shouldn’t waste our time. In IL Assembly, we have to do all the things manually, like pushing values to stack, managing memory etc. Think ILAsm same as that the assembly language but that assembly language deals with native Windows executables and this assembly (ILAsm) deals with .NET executables and also, this assembly is a bit easier and object oriented as well. So let’s start the beginning of this language with our first example program which will print a single phrase on the screen (console). It is a tradition that the beginning of every language includes a hello world program so we are going to do the same, but the phrase is changed. //Test.IL
//A simple programme which prints a string on the console
.assembly extern mscorlib {}
.assembly Test
{
.ver 1:0:1:0
}
.module test.exe
.method static void main() cil managed
{
.maxstack 1
.entrypoint
ldstr "I am from the IL Assembly Language..."
call void [mscorlib]System.Console::WriteLine (string)
ret
}
Figure 1.1 A sample Test program in ILAsm Write the above code (of fig 1.1) in a simple text editor like notepad and save as Test.il. Now let we first compile and run this code and then we will go into details of this. To compile the code, type the following on command prompt ILAsm Test.il (See the screen shot below)
Figure 1.2 Output of Sample Test Program. You can see the command I used to compile the code. ILAsm.exe is a command line tool shipped with the .NET Framework and can be located at
By reading the above lines, you may have an idea that how to write code in ILAsm language. And you might have some idea that ILAsm is not like the high level .NET languages (VB, C#). Anyway, whatever the code you write, you have to follow the structure of this kind (or a little changed when working with classes). Now there are a few things need more discussion. The mainly evaluation stack so, let's do that first. Evaluation StackThe evaluation stack can be considered as the normal machine stack, the stack used to store information just before the execution of a statement. We know that the information is stored in the memory when we have to perform some operation on them. Same as we move values to the registers in assembly language before invoking some instruction/interrupt. In the same way we have to move the information (a string in the case of our above example) to the stack before processing (output to screen in above case) that. In the start of our method main (figure 1.1), we notified the runtime of .NET that we are in need to store some information during the course of our method. We said that we will move only one value to stack at one time using Let's take another example which will clear the evaluation stack concept to us. //Add.il
//Add Two Numbers
.assembly extern mscorlib {}
.assembly Add
{
.ver 1:0:1:0
}
.module add.exe
.method static void main() cil managed
{
.maxstack 2
.entrypoint
ldstr "The sum of 50 and 30 is = "
call void [mscorlib]System.Console::Write (string)
ldc.i4.s 50
ldc.i4 30
add
call void [mscorlib]System.Console::Write (int32)
ret
}
Figure 1.3 Add.il Adding two predefined numbers. The portion above the main method is the same as that of our first example. Only the module name was changed. The thing to discuss is the Do not confuse with ldc.i4.s and ldc.i4, both represents to integer data type, but first one is of single byte and second of four byte. I hope that you have understood the way of using evaluation stack and also that how it works. Now let's move to discuss more things about the ILAsm language. IL Data TypesAs to learn any language, we first discuss the data types used in that language. So the same case is here. Let's take a look on the table below (figure 1.4) to know about the data types of IL Assembly. But before moving to that, I would like to point to one thing that there is no consistency in .NET data type definition in different languages. Like an integer (32 bit) in VB .NET is defined using Integer but in C# and VC++, it is int; though in both cases it is representing System.Int32. And also, we need to remember that is it Common Language Specification (CLS) Compliant or not. Like the UInt32 which is not recognized by VB .NET and also it is not CLS Compliant. Well, let's start to remember the table which provides new names of the data types for ILAsm Language.
Figure 1.4 Datatypes in ILAsm We also have some mnemonics of the data types in ILAsm like .i4, .i4.s, .u4 etc. as we used in the above example. Types listed above are those recognized by the ILAsm and also the table mentions that which types are CLS Compliant and which not. So, keeping in mind the above types, we can call any function like this call int32 SomeFunction (string, int32, float64<code lang=msil>)
Which means, the function //In C#
ColorTranslator.FromHtml(htmlColor)
//In ILAsm
call instance string [System.Drawing]
System.Drawing.ColorTranslator::ToHtml(valuetype
[System.Drawing]System.Drawing.Color)
Note that we explicitly defined the parameter types. We also defined the namespace where that type reside and a keyword value-type which flags that we are about to reference any non basic data type. The things will be clearer in the coming section when we will write a sample program which will deal with the types. But first, let's take a look at the basics of the language like variable declaration, loops, conditions etc. Variable DeclarationVariables are the major part of any programming language and hence, ILAsm also provides us a way to declare and use variables. Though not so simple as that in higher languages (VB .NET, C#) .locals directive can be used to declare the variables. This directive should usually occur on the beginning of any method though you can put your declaration at any place, but obviously, before using them. Here is a sample which can declare the variable, sets the values and then use them to print. .locals init (int32, string)
ldc.i4 34
stloc.0
ldstr "Some Text for Local Variable"
stloc.1
ldloc.0
call void [mscorlib]System.Console::WriteLine(int32)
ldloc.1
call void [mscorlib]System.Console::WriteLine(string)
Figure 1.5 Local variables We declared two variables using .locals directive, one of type I didn't use variable names here. Since those are local and we are not intended to expose them out of the method. But it doesn't mean that you can not declare variables by name. Sure, you can. To declare local variables you can name the variables with their data types, just like in C# like .locals init (int32 x, int32 y) And later, you can load or set the values of these variables using the same statements, but with variable names like Now you have the idea to handle the variables and stacks. Please review the codes provided above if you are facing any problem because after now, we will have some tough task while playing with the stack. We will frequently move data to memory and get back. So a good understanding of initializing variables, setting values to variables and loading values to stack from variables is necessary. Decisions / ConditionsDecisions or conditions are other necessary objects of any programming language. In the low level languages, like native Assembly language, the decisions are made using jumps (or branch). So the same is with the ILAsm. Take a look at the code snippet below. br JumpOver //Or use the br.s instead of br
//Other code here which will be skipped after getting br statement.
//
JumpOver:
//The statements here will be executed
Compare this statement with the //Branching.il
.method static void main() cil managed
{
.maxstack 2
.entrypoint
//Takes First values from the User
ldstr "Enter First Number"
call void [mscorlib]System.Console::WriteLine (string)
call string [mscorlib]System.Console::ReadLine ()
call int32 [mscorlib]System.Int32::Parse(string)
//Takes Second values from the User
ldstr "Enter Second Number"
call void [mscorlib]System.Console::WriteLine (string)
call string [mscorlib]System.Console::ReadLine ()
call int32 [mscorlib]System.Int32::Parse(string
)
ble Smaller
ldstr "Second Number is smaller than first."
call void [mscorlib]System.Console::WriteLine (string)
br Exit
Smaller:
ldstr "First number is smaller than second."
call void [mscorlib]System.Console::WriteLine (string)
Exit:
ret
}
Figure 1.6 Branching.il (only main method, included) The above program takes two values from the user and then check for the smaller number. The statement which needs attention is the “ble Smaller” which instructs the compiler to check if the first value in the stack is less than or equal to second, then it should branch to Smaller label. And if it is not then no branching will take place and the next statement will be executed which is to load a string and then to print that out. After this, an unconditional branching is occurred which was necessary because if that is not here then according to the flow of program, the statement after the Smaller label will be executed. So, we issued “br Exit” which caused the program to branch to Exit label and executed the ret statement. Other conditions includes LoopsAnother part of the basics of language is the Loops. Loop is nothing but the repetition of the same block of code again and again. It involves the branching actually depending on the value of a variable called loop index. Again, you have to look at a code and have to spend a little time to understand that how the loops work. .method static void main() cil managed
{
//Define two local
variables .locals init (int32, int32)
.maxstack 2
.entrypoint
ldc.i4 4
stloc.0 //Upper limit of the Loop, total 5
ldc.i4 0
stloc.1 //Initialize the Starting of loop
Start:
//Check if the Counter exceeds
ldloc.1
ldloc.0
bgt Exit //If Second variable exceeds the first variable, then exit
ldloc.1
call void [mscorlib]System.Console::WriteLine(int32)
//Increase the Counter
ldc.i4 1
ldloc.1
add
stloc.1
br Start
Exit:
ret
}
Figure 1.7 Loops.il (only main method) While the same code may written in higher languages, like C#, should look like this for (temp=0; temp <5; temp++)
System.Console.WriteLine (temp)
Let's examine the code. First of all, we declared two local variables and initialized the first variable with value of 4 and also the second variable with zero. The real loop starts from the Start Label, from where first we checked either the loop counter (variable 2, ldloc 1) exceeds the upper limit of loop (variable 1, ldloc 0), if that is the case then program will jump to Exit label which will cause to terminate the program. If this is not the case, then the value will be printed on the screen and one increment will be made in the variable and code will jump to Start label again to perform check if counter exceeds the upper limit or not. This is the way the loops works in ILAsm. Defining MethodsWe have seen about the decisions (conditions or branching), Loops and also declaring variables. Now is the time to see that how methods can be created in the ILAsm. The method of declaring methods in ILAsm is almost the same, and I hope that you have guessed till now, as that in C# or C++ but with a little changes. So, let's look at the code snippet first then we will discuss what we did. //Methods.il
//Creating Methods
.assembly extern mscorlib {}
.assembly Methods
{
.ver 1:0:1:0
}
.module Methods.exe
.method static void main() cil managed
{
.maxstack 2
.entrypoint
ldc.i4 10
ldc.i4 20
call int32 DoSum(int32, int32)
call void PrintSum(int32)
ret
}
.method public static int32 DoSum (int32 , int32 ) cil managed
{
.maxstack 2
ldarg.0
ldarg.1
add
ret
}
.method public static void PrintSum(int32) cil managed
{
.maxstack 2
ldstr "The Result is : "
call void [mscorlib]System.Console::Write(string)
ldarg.0
call void [mscorlib]System.Console::Write(int32)
ret
}
Figure 1.7 Methods.il Define and call your own methods A simple program which adds two numbers (pre defined, for the sake of simple code) and print the result. We defined two methods here. Note that both methods are static so that we can directly use them without creating any instance. First we loaded two numbers on the stack and called the first method The above way says that creating method is not a hard task in ILAsm. Yes, actually it is. But methods do get values by reference. So let’s take a look on that too. Passing Variables by ReferenceIL also supports the by reference values and of course it should because high level languages in .NET supports by reference arguments and the code from high level languages is converted to IL code and we are discussing IL Assembly language which produces the same IL code. Whenever we pass any variable by reference, then the address of the memory location, where that variable value was stored, is passed in contrast to the by value method, in which the copy of the value is passed to the function. Let's see an example of how by reference approach works in IL Assembly. .method static void main() cil managed
{
.maxstack 2
.entrypoint
.locals init (int32, int32)
ldc.i4 10
stloc.0
ldc.i4 20
stloc.1
ldloca 0 //Loads the address of first local variable
ldloc.1 //Loads the value of Second Local Variable
call void DoSum(int32 &, int32 )
ldloc.0
//Load First variable again, but value this time, not address
call void [mscorlib]System.Console::WriteLine(int32)
ret
}
.method public static void DoSum (int32 &, int32 ) cil managed
{
.maxstack 2
.locals init (int32)
//Resolve the address, and copy value to local variable
ldarg.0
ldind.i4
stloc.0
ldloc.0
//Perform the Sum
ldarg.1
add
stloc.0
ldarg.0
ldloc.0
stind.i4
ret
}
Figure 1.8 MethodRef.il Passing variables by reference. The interesting thing in the above example is the use of some new instructions like This was the way the ILAsm deals with the by reference variables. Up to here, we have seen the methods of playing with variable declaration, conditions, loops and methods (by value parameters and by reference parameters). Now is the time to declare our namespaces and classes using ILAsm language. Creating Namespaces and ClassesYes, and of course, it is possible in ILAsm to create your classes and namespaces. Actually, it is fairly easy to create your class or namespace in ILAsm as that in any higher level language. Don't believe? Then let's see. //Classes.il
//Creating
Classes
.assembly extern
mscorlib {} .assembly Classes
{ .ver 1:0:1:0 }
.module Classes.exe
.namespace HangamaHouse
{
.class public ansi auto Myclass extends [mscorlib]System.Object
{
.method public static void main() cil managed
{
.maxstack 1
.entrypoint
ldstr "Hello World From HangamaHouse.MyClass::main()"
call void [mscorlib]System.Console::WriteLine(string)
ret
}
}
}
Figure 1.9 Classes.il Creating your own namespace and class. I think, now it is not much needed to explain the code. The thing is very simple, .namespace directive, followed by a name Here I would like to mention that all classes you create are inherited from the There were two more keywords used in the above class creation, those are ansi and auto. Ansi tells that all the strings in the class should be converted to ANSI strings. Other options for this are unicode and autochar (conversion will be determined automatically according to platform). Second one is auto keyword which specifies that the runtime will automatically choose appropriate layout for members of the object in unmanaged memory. Other options for this are sequential (members are laid out sequentially) and explicit (layout is explicitly defined). For more information, see Scope of the Objects (Member Accessibility Flags)The following table summarizes the scope of the Classes in ILAsm.
Figure 1.10 The Member accessibility flags for ILAsm There are some more scopes which can be used with the methods and fields (variables in the class). You can find out the complete list in the MSDN. Creating and Using Class ObjectsIn this section of my article, I will show you that how can you create the instance of your class and use in ILAsm code. Before this, you have seen that how to create your own namespaces and classes in ILAsm. But creating something is useless until we can't use that. So, let's begin to create a simple class and use that. Let's create our own library in ILAsm. This simple library contains only one public method. That is, it will receive one value and will return the square of that value. Simple is the best to understand. Look at the code. .assembly extern mscorlib {}
.assembly MathLib
{
.ver 1:0:1:0
}
.module MathLib.dll
.namespace HangamaHouse
{
.class public ansi auto MathClass extends [mscorlib]System.Object
{
.method public int32 GetSquare(int32) cil managed
{
.maxstack 3
ldarg.0 //Load the Object's 'this' pointer on the stack
ldarg.1
ldarg.1
mul
ret
}
}
}
Figure 1.11 the MathLib.il Library for math operation Square Note: Compile above code to a DLL file. Use ILAsm MathLib.il /dll The code looks simple. It defines one namespace with the name HangamaHouse and one class inside that namespace, named MathClass, which extends from the Object class of System namespace as our above class (in figure 1.10) do. Now within that class, we defined one method named GetSquare which takes one argument of type int32. We defined the The library building was no matter. Simple yet, now let's look at the example which uses this library .assembly extern mscorlib {}
.assembly extern MathLib {.ver 1:0:1:0}
//
//rest code here
//
.method static void Main() cil managed
{
.maxstack 2
.entrypoint
.locals init (valuetype [MathLib]HangamaHouse.MathClass mclass)
ldloca mclass
ldc.i4 5
call instance int32 [MathLib]HangamaHouse.MathClass::GetSquare(int32)
ldstr "The Square of 5 Returned : "
call void [mscorlib]System.Console::Write(string)
call void [mscorlib]System.Console::WriteLine(int32)
ret
}
Figure 1.12 Using the MathLib library's Class MathClass First two lines of this method are simple. Come to third line where we defined a local variable of type So the main thing here was to declare the object of the class which was done using .locals directive and In the same way, we can use properties and constructors in the class and can call them in our code. Next section of my article describes that how can you create your private fields, constructors and properties in ILAsm language and how can you call them using the same ILAsm code. Creating Constructors and PropertiesConstructor is actually a method which is called in high level languages whenever the object of the some class is created. But in low level languages like ILAsm, you manually have to call them though there is no doubt that it is a methods which always returns nothing. The sample code below demonstrates how to create constructors. I am including only the necessary part here, the source code with this article includes complete code for this section. Please be attentive while reading this section because this section will teach you a lot of things. .class public MathClass extends [mscorlib]System.ValueType
{
.field private int32 mValue
//Other code goes here
.method public specialname rtspecialname
instance void .ctor() cil managed
{
ldarg.0
ldc.i4.s 15
stfld int32 HangamaHouse.MathClass::mValue
ret
}
//Other code goes here.
Figure 1.13 The constructor for the First thing you may notice here is that I used to inherit my class from After the declaration of the class, I declared a private field named mValue (private variable in high level languages). Then I declared a constructor using .method directive. Remember, constructor is a method. Now you will surprise that the .ctor is used instead the name of the class (as in high level languages like C++). Yes, the .ctor represents the constructor method in ILAsm. This is the default constructor since it takes no parameter. What we did there is, loaded the reference of object itself (this) using ldarg.0 statement, then we loaded an integer of value 15 and assigned that value to our private field mValue. stfld statement can be used to set the value of any field. We provided it the complete signature of the field. I think you should not surprise now that why we did so. Finally, we returned from the method (constructor). You should also notice that we used a couple of more keywords in the declaration of this constructor. Those are Unlike the high level languages, in ILAsm constructor is not called automatically. You explicitly have to call it. Here is a code snippet which calls the constructor to initialize the value of the class. .method public static void Main() cil managed
{
.maxstack 2
.entrypoint
.locals init (valuetype [MathLib]HangamaHouse.MathClass mclass)
ldloca mclass
call instance void [MathLib]HangamaHouse.MathClass::.ctor()
The above code creates a local variable named mclass of type As about the properties, so the properties are also the methods actually. See the figure and then we will be able to understand that fully. .method specialname public instance int32 get_Value() cil managed
{
ldarg.0
ldfld int32 HangamaHouse.MathClass::mValue
ret
}
.method specialname public instance void set_Value(int32 ) cil managed
{
ldarg.0
ldarg.1
stfld int32 HangamaHouse.MathClass::mValue
ret
}
//Define the property, Value
.property int32 Value()
{
.get instance int32 get_Value()
.set instance void set_Value(int32 )
}
Figure 1.15 Properties You can examine the code above and can surely say that it is the same as that of methods code. But you can see one another thing here; that is .property directive. It defines two things inside its body. That is, the property get and property set. This actually marks the methods as the part of the property and put them under one tree. Since we can see that the both methods are defined above, the .maxstack 2 .locals
init (valuetype [MathLib]HangamaHouse.MathClass tclass)
ldloca tclass
ldc.i4 25
call instance void [MathLib]HangamaHouse.MathClass::set_Value(int32)
ldloca tclass
call instance int32 [MathLib]HangamaHouse.MathClass::get_Value()
ldstr "Propert Value Set to : "
call void [mscorlib]System.Console::Write(string)
call void [mscorlib]System.Console::WriteLine(int32)
Figure 1.16 Using Properties. Also a method is called in this code Not surprising. We created the instance of the class and then called the Up to here, we have covered a lot of things which may help you to start working in ILAsm language. But there is one necessary thing left, the errors and debugging. Creating Windows Form (Frame)This section demonstrate that how can you combine the information provided above to create a simple GUI, the Windows Form. In this application, I have created a simple form from .namespace MyForm
{
.class public TestForm extends
[System.Windows.Forms]System.Windows.Forms.Form
{
.field private class [System]System.ComponentModel.IContainer components
.method public static void Main() cil managed
{
.entrypoint
.maxstack 1
//Create New Object of TestForm Class and Call the Constructor
newobj instance void MyForm.TestForm::.ctor()
call void [System.Windows.Forms]
System.Windows.Forms.Application::Run(
class [System.Windows.Forms]System.Windows.Forms.Form)
ret
}
Figure 1.17 Windows Form's EntryPoint Method This is the entry point of our application. First of all (after creating class .method public specialname rtspecialname instance
void .ctor() cil managed
{
.maxstack 4
ldarg.0
//Call Base Class Constructor
call instance void [System.Windows.Forms]
System.Windows.Forms.Form::.ctor()
//Initialize the Components
ldarg.0
newobj instance void [System]System.ComponentModel.Container::.ctor()
stfld class [System]System.ComponentModel.IContainer
MyForm.TestForm::components
//Set the Title of the Window (Form)
ldarg.0
ldstr "This is the Title of the Form...."
call instance void [System.Windows.Forms]
System.Windows.Forms.Control::set_Text(string)
//Set the Back Color of the Form
ldarg.0
ldc.i4 0xff
ldc.i4 0
ldc.i4 0
call valuetype [System.Drawing]System.Drawing.Color
[System.Drawing]System.Drawing.Color::FromArgb(
int32, int32, int32)
call instance void [System.Windows.Forms]
System.Windows.Forms.Control::set_BackColor(
valuetype [System.Drawing]System.Drawing.Color)
//Maximize the Form using WindowState Property
ldarg.0
ldc.i4 2 //2 for Maximize
call instance void [System.Windows.Forms]
System.Windows.Forms.Form::set_WindowState(
valuetype [System.Windows.Forms]
System.Windows.Forms.FormWindowState)
ret
}
Figure 1.18 .ctor method (Constructor) of Very simple, we simply called the base class's .ctor method (constructor). Then we created the object of Container and assigned that to out component object (field of our class). Form initialization completed here. Now we are moving to set some properties of our new form. First of all we are going to set the title of our form (Text property). We loaded a string to stack and called the Although, the code for creating a Windows Form finishes here, but we can also define the .method family virtual instance void Dispose(bool disposing) cil managed
{
.maxstack 2
ldarg.0
ldfld class [System]System.ComponentModel.IContainer
MyForm.TestForm::components
callvirt instance void [mscorlib]System.IDisposable::Dispose()
//Call Base Class's Dispose Event
ldarg.0
ldarg.1
call instance void [System.Windows.Forms]
System.Windows.Forms.Form::Dispose(bool)
ret
}
The So, creating the user interface was not very hard task (though a little). From here, you can code to add components such as textboxes, labels etc in your form and also can code at their events. Can you? Errors and DebuggingErrors are the part of any programming language. So ILAsm is not excluded. Like errors of other programming languages, in ILAsm you may also encounter with Compiler errors (normally known as syntax error), runtime errors and logical errors. I am not going in details that what these errors are since all of you know them very well. The purpose of this section is to introduce some tools and techniques which may help you to debug your program. First of all, you can generate debug info file while compiling your code. Just use the /debug switch with ILAsm.exe while compiling your code like ILAsm.exe Test.il /debug
This will produce one exe file of name Text.exe and also one debug information file Test.pdb. Now this file can be used to later debug your application. You can use a tool to verify your application (an assembly actually). That is PE Verify (peverify.exe), shipped with .NET Framework SDK and you can locate that at C:\Program Files\Microsoft .NET\Framework SDK\Bin folder (by default). Pre Verify tool do not use source code to verify the assembly, but it actually takes an exe to examine if the compiler has emitted the invalid code. There may be some case when you need to verify your assembly like you may be using some third party compiler or writing your own. Usage is very simple. Consider the example below. peverify.exe Test.exe
For more information and options, you can see command line switches of peverify.exe using peverify.exe You can also get the IL code from any of your .pre-compiled EXE or DLL (in .NET) using ILDasm.exe. ILDasm.exe is another valuable tool shipped with .NET Framework SDK which can help to debug your applications at low level. This tool is useful to you if you have written your code in any high level .NET language and want to see what IL code was generated by your compiler. It can be located under the same folder as that peverify.exe (Framework SDK\Bin folder). You can get IL code of any of your .NET EXE file using this way. ILDasm.exe SomeProject.exe /out:SomeProject.il
There are a number of other tools which can be used to debug your .NET applications like DbgClr.exe, CorDbg.exe. You can find their reference from MSDN, .NET Framework SDK or can search the web for third party. SummaryIn this article we learned the basics of ILAsm and wrote some programs using ILAsm language. We started from the basics of ILAsm and that why it is needed. Then we wrote a sample test program which prints a single line on the console. We learned a little about the Evaluation stack and also saw via a simple code (adding numbers) that how it works. Then we gathered knowledge about IL data types and used them to declare variables, applying conditions, creating loops etc. We also defined methods and after that we switched to the namespace and class creation. There we created the objects of our own classes and used them. Also we created the constructors and properties for our classes. ConclusionWriting code in ILAsm is not a simple task. As there were a number of things not discussed in this article like arrays, error handling etc. But after getting familiar with ILAsm, you can proceed to work on them yourself. ILAsm can be helpful to you if you want to debug your code at low level or if you are planning to write some compiler for .NET platform. If you are just a beginner in .NET then I will not recommend you to go through this process since it needs a good understanding of .NET, but it will give you better understanding that how .NET Common Language Runtime is working behind the scene. About the AuthorSameers (theAngrycodeR) has did his Master in Computer Sciences in Feb. 2002. He is the Project Manager in City Soft (Pakistan) and has developed and managed a number of projects. He proved his expertise in Visual Basic 6 and now working in VB .NET. He is the author of many articles on CodeProject.com as well as on the Microsoft .NET Community Site, GotDotNet. Also submitted many source codes on Planet-Source-Code.com. The complete information about the author can be found here.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||