Introduction to MSIL – Part 1 – Hello World

When describing C++/CLI and how it relates to C#, I am often tempted to discuss the Microsoft intermediate language (MSIL) that the Visual C++ and Visual C# compilers generate. The trouble is that most programmers are not familiar with MSIL and programs like ILDASM aren’t that helpful to the newbie because the MSIL they display, although painfully correct, is not very readable. For this reason I decided to post a few entries introducing MSIL at a basic level. Since I doubt anybody reading this will actually go and start writing code in MSIL, I will skim over some of the uninteresting details and focus on things like defining types, writing methods, calling instructions and handling exceptions.

Please let me know if you find this helpful.

Let’s start with a simple main (entry point) function that displays a really unique message. Unlike C#, CLI does not have any requirement that a method must belong to a class. The entry point function also does not have to be called main; however I will use this name in this series for simplicity.

.method static void main()
{
    .entrypoint
    .maxstack 1

    ldstr "Hello world!"
    call void [mscorlib]System.Console::WriteLine(string)

    ret
}

The main method above is called a method definition since both the signature as well as the body of the method is provided. In contrast, when a method signature is provided without a body it is referred to as a method declaration. Method declarations are typically used as call targets (when a method is being called) whereas a method definition provides the actual implementation for a method.

A method definition begins with the .method directive and can be defined at global scope or within a class. The application entry point must be static, meaning an instance is not required to call the method, and that is indicated by the static keyword. Declaring a global method static seems redundant but the ILASM compiler complains if you omit the static keyword in some cases. Think of ‘void main()’ as the signature of the method which, as you would expect, indicates that it does not return a value and takes zero arguments.

The .entrypoint directive signals to the runtime that this method is the entry point for the application. Only one method in the application can have this directive.

The .maxstack directive indicates how many stack slots the method expects to use. For example, adding two numbers together involves pushing both numbers onto the stack and then calling the add instruction which pops both numbers off the stack and pushes the result onto the stack. In that example you will need two stack slots.

The ldstr instruction pushes the string that is passed to the WriteLine method onto the stack. The call instruction invokes the static WriteLine method on the System.Console class from the mscorlib assembly. This is an example of a method declaration. It provides the full signature of the WriteLine method (including the string argument) so that the runtime can determine which overload of the WriteLine method to call.

And finally the ret instruction returns execution to the caller. In the case of the entry point method, this would bring your application to an end.

Read part 2 now: Using Local Variables


© 2004 Kenny Kerr

 

6 Comments

Comments have been disabled for this content.