Getting Started With .NET IL
Written by Mike James   
Friday, 10 December 2021
Article Index
Getting Started With .NET IL
Basic IL
A sohisticated stack

 

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 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 Arith.il. 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()
 {
  ret
 }
 .method public float32 Add(float32,float32)
 {
  ldarg.1
  ldarg.2
  add
  ret
 }
}

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
 {
  .entrypoint
  newobj instance void Arith::.ctor()
  ldc.r4 0.1
  ldc.r4 0.2
  call instance float32
  Arith::Add(float32,float32)
  call void [mscorlib]System.Console::
  WriteLine(float32)
  ret
 }
}

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.

 

  • Mike James, Founder and Chief Editor of I Programmer is a prolific author. In Deep C#: Dive Into Modern C#, published in September 2021, he provides a “deep dive” into various topics that are important or central to the language. By exploring the motivation behind these key concepts, which is so often ignored in the documentation, the intention is to be thought-provoking and to give developers confidence to exploit C#’s wide range of features.

 

netlogo

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, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

raspberry pi books

 

Comments




or email your comment to: comments@i-programmer.info

Banner


Deep C# - Casting the Escape from Strong Typing

Casting is one of the most confusing aspects of any modern language and it often makes beginners think hard. But if you know why you are doing it, then the how makes a lot more sense. We have encounte [ ... ]



Deep C# - Interface

Interfaces - what are they for? Not quite inheritance yet they seem to fit the same purpose. Find out in this extract from my new book, Deep C#: Dive Into Modern C#.


Other Articles

<ASIN:1871962714>

<ASIN:B09FTLPTP9>

 



Last Updated ( Friday, 10 December 2021 )