Article Options
Premium Sponsor
Premium Sponsor

 »  Home  »  .NET Framework  »  Demystifying Microsoft Intermediate Language. Part 2 - A Short Description of .NET Application
Demystifying Microsoft Intermediate Language. Part 2 - A Short Description of .NET Application
by Kamran Qamar | Published  10/21/2002 | .NET Framework | Rating:
Kamran Qamar

Kamran Qamar is independent consultant with extensive experience in all facets of software development life cycle (SDLC). He specializes in web-enabled application development using Microsoft tools and technologies. He has spent last seven years architecting and developing web based telemetry and management applications around the world. Recently he delivered Bridge Management System for Ukrainian government built on .NET technologies.

Kamran also enjoys teaching and presenting on .NET technologies. He has Electronic Engineering background and has Master degree in computer sciences.

 

View all articles by Kamran Qamar...
Demystifying Microsoft Intermediate Language. Part 2 - A Short Description of .NET Application

A Short Description of .NET Application

A .NET application consists of one or more executables, each of which carries metadata and optional managed code. Managed .NET Applications is called assembly. An assembly is a set of one or more files deployed as a unit. An assembly always contains a manifest that specifies

  • Version, name, culture, and security requirements for the assembly.
  • Which other files, if any, belong to the assembly along with a cryptographic hash of each file. The manifest itself resides in the metadata part of a file and that file is always part of the assembly.
  • Which of the types defined in other files of the assembly are to be exported from the assembly. Types defined in the same file as the manifest are exported based on attributes of the type itself.
  • Optionally, a digital signature for the manifest itself and the public key used to compute it.

Where executable contents are referred as modules. We can have single module assembly or multi module assembly. An assembly contains only one manifest amongst all its constituent files. For an assembly to be executed (rather than dynamically loaded) the manifest resides in the module that contains the entry point. Following figure shows the structure of a single assembly, .NET Application:

In next article, we will discuss more about a .NET Application format and see how multi-module assemblies are created. For the current discussion it is sufficient to know that one single assembly application has assembly identification section, known as manifest, metadata section and IL code section.

Keeping this short narrative in perspective to our example in hand, we realize that our sample application does have an assembly section defined using assembly directive. However it is not complete as it doesn't hold information for version, name, culture, security, and module information. In next few lines of code I will update our example code to accommodate this information.

.assembly DemystifyingILChapter1 
{
    .hash algorithm 0x00008004
    .ver 1:0:0:0
}
.class public auto ansi HelloWorld extends [mscorlib]System.Object
{
    .method static void  HelloWorld()
    {
        .entrypoint
        ldstr "Hello World."
        call void [mscorlib]System.Console::WriteLine(class System.String)
        ret
    }
    .method public hidebysig specialname rtspecialname 
        instance void  .ctor() cil managed
    {
        ldarg.0
        call instance void [mscorlib]System.Object::.ctor()
        ret
    } 
}

In this code, I expanded assembly directive, which marks the beginning of a manifest. assembly directive can have number of other directives in it. I have used two, they are:

  • hash: This directive tell VSE which hashing algorithm we are using to implement security. Number 0x00008004 means hashing is implemented using SHA1 which is default. All assemblies have to implement hashing using this same algorithm.
  • ver: The version number of the assembly, specified as four 32-bit integers with colon ":" separating them (00:00:00:00). These four integers represent major version number, minor version, build and revision number.

While discussing format of a .NET application, we also mentioned that an executable application contain reference to module. Until now we haven't used any directive to tell assembler which module to build. In our program, we are referring to an external program (mscorlib). Then assembler is compiling our code correctly?

Well, ILAsm.exe utility is intelligent enough to automatically define our code as prime module and reference it to mscorlib assembly. We will make assembler's job easy and will create directive for these two our self. To reference an external assembly we will again use directive assembly with attribute extern. To proper reference an assembly, .NET framework minimum requirement is originator's public key or public key token and the version of that assembly. Public Key token is lower 8 bits of SHA1 hash code which uniquely identify the assembly. We can find this information about our referenced by pointing window explorer to C:\WinNT\assembly folder as shown in figure below:

From the figure we can see for our assembly mscorlib, I have version 1.0.3300.0 installed with public key token B77A5C561934E089. Your computer might have different version of mscorlib installed. Please check it out and update code with that value.

Our updated code with these two directive added will look like this:

.module Hello.exe
.assembly extern mscorlib
{
    .publickeytoken = (B7 7A 5C 56 19 34 E0 89)
    .ver 1:0:3300:0
}
.assembly DemystifyingILChapter1 
{
    .hash algorithm 0x00008004
    .ver 1:0:0:0
}
.class public auto ansi HelloWorld extends [mscorlib]System.Object
{
    .method static void  HelloWorld()
    {
        .entrypoint
        ldstr "Hello World."
        call void [mscorlib]System.Console::WriteLine(class System.String)
        ret
    }
}

Now we have a proper .NET application ready, with all the information needed by .NET framework hand coded into it. Next we will write same HelloWorld Application in C# and VB.NET and will compare IL code generated by respective compilers.

Hello World Program in High Level Languages

We will create simple HelloWorld application in C# and VB. We will then compile each of them into executable files. Once the executable files are created we will disassemble them using ildasm.exe utility. We will compare the two outputs, one from C# program other from VB.NET program and will see if we can correlate them with IL program we produced previously.

C#

Lets write the same program using C#. The code listing is given below:

public class HelloWorld
{
    public static void Main()
    {
        System.Console.WriteLine("Hello World.");
    }
}

We can compile this program using csc.exe (C-Sharp compiler). Now, we will run ildasm.exe program on the newly created HelloWorld.exe file by using following command line:

ildasm /out = Helloworld.txt HelloWorld.exe

This creates a text file Helloworld.txt with following contents:

//  Microsoft (R) .NET Framework IL Disassembler.  Version 1.0.3705.0
//  Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.

.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )              // .z\V.4..
  .ver 1:0:3300:0
}
.assembly HelloWorld
{
  // --- The following custom attribute is added automatically, ---
  // --- do not uncomment -------
  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::
  //                                 .ctor(bool, bool) = ( 01 00 00 01 00 00 ) 
  .hash algorithm 0x00008004
  .ver 0:0:0:0
}
.module HelloWorld.exe
// MVID: {E63F9CA9-D4C4-4826-9BE1-2B0EE3694289}
.imagebase 0x00400000
.subsystem 0x00000003
.file alignment 512
.corflags 0x00000001
// Image base: 0x03000000
//
// ============== CLASS STRUCTURE DECLARATION ==================
//
.class public auto ansi beforefieldinit HelloWorld
       extends [mscorlib]System.Object
{
} // end of class HelloWorld


// =============== CLASS MEMBERS DECLARATION ===================
//   note that class flags, 'extends' and 'implements' clauses
//          are provided here for information only

.class public auto ansi beforefieldinit HelloWorld
       extends [mscorlib]System.Object
{
  .method public hidebysig static void  Main() cil managed
  {
    .entrypoint
    // Code size       11 (0xb)
    .maxstack  1
    IL_0000:  ldstr      "Hello World."
    IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000a:  ret
  } // end of method HelloWorld::Main

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // Code size       7 (0x7)
    .maxstack  1
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ret
  } // end of method HelloWorld::.ctor

} // end of class HelloWorld


// =============================================================

//*********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file HelloWorld.res

Visual Basic .NET

Lets write same program in VB.NET, the listing is given below.

Public Class HelloWorld
    Public Shared Sub Main
        System.Console.WriteLine ("Hello World From VB.NET")
    End Sub
End Class

Compile this code using vbc.exe (VB Compiler) and dissemble it as shown before. The content of the output file will be:

//  Microsoft (R) .NET Framework IL Disassembler.  Version 1.0.3705.0
//  Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.

.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )            // .z\V.4..
  .ver 1:0:3300:0
}
.assembly extern Microsoft.VisualBasic
{
  .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )            // .?_....:
  .ver 7:0:3300:0
}
.assembly HelloWorld
{
  .hash algorithm 0x00008004
  .ver 0:0:0:0
}
.module HelloWorld.exe
// MVID: {BAFC36F6-4629-4BBB-88B9-B76B8D39C758}
.imagebase 0x00400000
.subsystem 0x00000003
.file alignment 512
.corflags 0x00000001
// Image base: 0x03000000
//
// ============== CLASS STRUCTURE DECLARATION ==================
//
.class public auto ansi HelloWorld
       extends [mscorlib]System.Object
{
} // end of class HelloWorld

// =============================================================

// =============== CLASS MEMBERS DECLARATION ===================
//   note that class flags, 'extends' and 'implements' clauses
//          are provided here for information only

.class public auto ansi HelloWorld
       extends [mscorlib]System.Object
{
  .method public specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       7 (0x7)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ret
  } // end of method HelloWorld::.ctor

  .method public static void  Main() cil managed
  {
    .entrypoint
    .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = (01 00 00 00)
    // Code size       11 (0xb)
    .maxstack  8
    IL_0000:  ldstr      "Hello World From VB.NET"
    IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000a:  ret
  } // end of method HelloWorld::Main

} // end of class HelloWorld


// =============================================================

//*********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file HelloWorld.res

When you read the above two files, you will realize that all of this has already been explained earlier :) And the output from both VB.NET and C# compilers is almost identical. I used this example to show that, irrespective of the language you use, ultimately the source code will get converted to IL code. Thus the difference between programming languages has now become a superficial issue.

In the next articles to come, I will introduce you to IL instruction set, how IL is used to perform basic operations like Selection, Iteration, overloading etc. We will also see how to create reference and value type. Define methods, properties and indexers. I will show you the basic of exception handling and creating special classes like delegates and define custom events. I will finish this series with a full functional GUI application written in IL.

But to do all this I need your support and interest. You can post your comments and suggestion here or email me at kamran@kenlogix.com


Related devCity.NET articles:

How would you rate the quality of this article?
1 2 3 4 5
Poor Excellent
Tell us why you rated this way (optional):

Article Rating
The average rating is: No-one else has rated this article yet.

Article rating:2.69767441860465 out of 5
 43 people have rated this page
Article Score23237
Sponsored Links