Article Index


Local variables

As well as the stack there are local variables, data structures and fields.

But notice that in principle you can write any program using just the stack.

For example to declare local variable called Total you would add:

.locals init(float32 Total)

The “init” is a modifier that indicates that the variables have to be initialised before use.

To load the result of the addition you have to use:

stloc Total
ldloc Total

before the call to WriteLine.

The instruction stloc, i.e. Store to Local, pops the top of the stack into Total. You need the ldloc instruction, i.e. LoaD from Local, to push the value back on the stack so that the WriteLine can use it.

It is more common to work with local variables just in terms of the index number. For example:

.locals init([0] float32 Total)

Defines Total to be local varible zero and you can load it onto the stack using any of:

ldloc 0
ldloc Total

Object oriented IL

Using a static object isn’t really the same thing as taking a full object-oriented approach – it’s just a way of writing a main program.

This next example is intended to give you an idea of the full extent of IL’s object facilities. Start a new program called First we have the usual declarations followed by a public class definition:

.assembly extern mscorlib {}
.assembly Arith{}
.module Arith.exe
.class public Arith
 .method public specialname void .ctor()
 .method public float32 Add(float32,float32)

The class has two methods .ctor which is its constructor – which does nothing in this case - and Add.

The Add method pushes its two parameters on the stack, using ldarg.n, adds them and leaves the result on the stack.

To try this class and its Add method out we use the static Main method again:

.class Test.Program
extends [mscorlib]System.Object
 .method static void Main(string[] args)
 cil managed
  newobj instance void Arith::.ctor()
  ldc.r4 0.1
  ldc.r4 0.2
  call instance float32
  call void [mscorlib]System.Console::

The newobj instruction creates an instance of the class and calls its creator, .ctor(). The result of newobj is a pointer to the instance stored on the top of the stack.

Now we can load the stack with two parameter values and call the instance of Add.

Notice that the instance of the class that is called is determined by the first argument, i.e. arg0, passed to the method. You can think of this as a “this” reference and note that instance methods have to explicitly use it to work with instance fields. If you assemble this program you will discover that it adds two numbers together as before.

IL supports instance and static methods and fields. It supports virtual and non-virtual methods and inheritance but this is beyond the scope of this introduction.

Where next?

Once you have the idea of the way that the object-oriented, strongly typed aspects of IL interact with the fact that it is a stack-oriented assembler you should find it easier to understand the documentation.

You can find some very dry technical definitions of how it all works at:

ECMA C# and Common Language Infrastructure Standards

Another good way of learning IL is to use the ILdasm tool, which you will find in the same directory as ILasm. This can be used to disassemble .NET programs and it provides lots of clues as to how the compilers use IL.


Related articles:

The LIFO Stack - A Gentle Guide

Introduction to data structures

Stack architecture demystified

Reverse Polish Notation - RPN

Brackets are Trees

Javascript data structures - Stacks 

Deep C#

The Heart Of A Compiler       

Assemblers and assembly language       



To be informed about new articles on I Programmer, install the I Programmer Toolbar, subscribe to the RSS feed, follow us on, Twitter, FacebookGoogle+ or Linkedin,  or sign up for our weekly newsletter.






or email your comment to: This email address is being protected from spambots. You need JavaScript enabled to view it.