CHAPTER 18 UNDERSTANDING CIL AND THE ROLE OF DYNAMIC ASSEMBLIES
Mapping Parameters to Local Variables in CIL
You have already seen how to declare local variables in raw CIL using the .locals init directive;
however, you have yet to see exactly how to map incoming parameters to local methods. Consider the
following static C# method:
public static int Add(int a, int b)
{
return a + b;
}
This innocent-looking method has a lot to say in terms of CIL. First, the incoming arguments (a and
b) must be pushed onto the virtual execution stack using the ldarg (load argument) opcode. Next, the
add opcode will be used to pop the next two values off the stack and find the summation, and store the
value on the stack yet again. Finally, this sum is popped off the stack and returned to the caller via the
ret opcode. If you were to disassemble this C# method using ildasm.exe, you would find numerous
additional tokens injected by csc.exe, but the crux of the CIL code is quite simple.
.method public hidebysig
int32 b) cil managed
{
.maxstack 2
ldarg.0
// Load "a"
ldarg.1
// Load "b"
add
// Add both
ret
}
static int32
Add(int32 a,
onto the stack.
onto the stack.
values.
The Hidden this Reference
Notice that the two incoming arguments (a and b) are referenced within the CIL code using their indexed
position (index 0 and index 1), given that the virtual execution stack begins indexing at position 0.
One thing to be very mindful of when you are examining or authoring CIL code is that every
nonstatic method that takes incoming arguments automatically receives an implicit additional
parameter, which is a reference to the current object (think the C# this keyword). Given this, if the Add()
method were defined as nonstatic, like so:
// No longer static!
public int Add(int a, int b)
{
return a + b;
}
the incoming a and b arguments are loaded using ldarg.1 and ldarg.2 (rather than the expected ldarg.0
and ldarg.1 opcodes). Again, the reason is that slot 0 actually contains the implicit this reference.
Consider the following pseudo-code:
// This is JUST pseudo-code!
.method public hidebysig static int32 AddTwoIntParams(
MyClass_HiddenThisPointer this, int32 a, int32 b) cil managed
{
ldarg.0
// Load MyClass_HiddenThisPointer onto the stack.
ldarg.1
// Load "a" onto the stack.
677