What is IL – practical example

I’m sure you know your C# code is not directly compiled into machine code and ran. It is first converted into IL. CIL to be precise. Its stands for Common Intermediate Language. This CIL is then assembled into bytecode and compiled by JIT (Just-in-time compiler) into executable machine code. So much for the theory, but have you ever tried to mess with IL yourself? Not? Lets try it.

Run the Visual Studio Command Prompt from the start menu. Find yourself suitable directory to tinker around. Create a program, compile it and run:

C:\Dev\ilmagic>copy con p.cs
public class p {
  public static void Main() {
    System.Console.WriteLine("Hello console!");
  }
}^Z
        1 file(s) copied.
C:\Dev\ilmagic>csc p.cs
Microsoft (R) Visual C# Compiler version 1.2.0.60317
Copyright (C) Microsoft Corporation. All rights reserved.
C:\Dev\ilmagic>p.exe
Hello console!

Now lets see inside the IL. You can use the ildasm decompiler you have on your machine. It can not only show you the decompiled code but also save it to the file. In order to do it issue the following command:

C:\Dev\ilmagic>ildasm p.exe /OUT=p.il

Now take a look inside the il file with any txt editor you like. Inside its intermediate code. It’s still readable and similar to assembler. Lets mess around. Look for the class definition:

.class public auto ansi beforefieldinit p
       extends [mscorlib]System.Object
{
  .method public hidebysig static void  Main() cil managed
  {
    .entrypoint
    // Code size       13 (0xd)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldstr      "Hello CIL!"
    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000b:  nop
    IL_000c:  ret
  } // end of method p::Main
  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method p::.ctor
} // end of class p

Looks vaguely familiar? You can even see the text that will be beamed into console. It is in line:

IL_0001:  ldstr      "Hello console!"

Lets change it to:

IL_0001:  ldstr      "Hello CIL!"

and save the file.

Assemble the IL back to the bytecode with ilasm.exe (it’s a part of .NET SDK – that’s why we are in VS command prompt):

C:\Dev\ilmagic>ilasm p.il /OUTPUT=p2.exe /EXE
Microsoft (R) .NET Framework IL Assembler.  Version 4.6.1038.0
Copyright (c) Microsoft Corporation.  All rights reserved.
Assembling 'p.il'  to EXE --> 'p2.exe'
Source file is ANSI
Assembled method p::Main
Assembled method p::.ctor
Creating PE file
Emitting classes:
Class 1:        p
Emitting fields and methods:
Global
Class 1 Methods: 2;
Emitting events and properties:
Global
Class 1
Writing PE file
Operation completed successfully

Voila and now lets run the exe (that’s the time where the JIT comes into play and creates machine code out of the CIL assembly).

C:\Dev\ilmagic>p2.exe
Hello CIL!

Nice! He?

Leave a Reply

Your email address will not be published. Required fields are marked *