The code at IL_000estarts out by loading two values onto the evaluation
stack: the value of local variable 0, which was just initialized earlier to 1, and
the constant 10. Then these two values are compared using the ble.sinstruc-
tion. This is a “branch if lower or equal” instruction that does both the com-
paring and the actual jumping, unlike IA-32 code, which requires two
instructions, one for comparison and another for the actual branching. The
CLR compares the second value on the stack with the one currently at the top,
so that “lower or equal” means that the branch will be taken if the value at
local variable ‘0’ is lower than or equal to 10. Since you happen to know that
the local variable has just been loaded with the value 1, you know for certain
that this branch is going to be taken—at least on the first time this code is exe-
cuted. Finally, it is important to remember that in order for ble.sto evaluate
the arguments passed to it, they must be popped out of the stack. This is true
for pretty much every instruction in IL that takes arguments through the eval-
uation stack—those arguments are no longer going to be in the stack when the
instruction completes.
Assuming that the branch is taken, execution proceeds at IL_0004, where
the routine calls WriteLine, which is a part of the .NET class library. Write
Linedisplays a line of text in the console window of console-mode applica-
tions. The function is receiving a single parameter, which is the value of our
local variable. As you would expect, the parameter is passed using the evalu-
ation stack. One thing that’s worth mentioning is that the code is passing an
integer to this function, which prints text. If you look at the line from where
this call is made, you will see the following: void [mscorlib]System.
Console::WriteLine(int32). This is the prototype of the specific func-
tion being called. Notice that the parameter it takes is an int32, not a string as
you would expect. Like many other functions in the class library, WriteLine
is overloaded and has quite a few different versions that can take strings, inte-
gers, floats, and so on. In this particular case, the version being called is the
int32version—just as in C++, the automated selection of the correct over-
loaded version was done by the compiler.
After calling WriteLine, the routine again loads two values onto the stack:
the local variable and the constant 1. This is followed by an invocation of the
addinstruction, which adds two values from the evaluation stack and writes
the result back into it. So, the code is adding 1 to the local variable and saving
the result back into it (in line IL_000d). This brings you back to IL_000e,
which is where you left off before when you started looking at this loop.
Clearly, this is a very simple routine. All it does is loop between IL_0004
and IL_0011and print the current value of the counter. It will stop once the
counter value is greater than 10 (remember the conditional branch from lines
IL_000ethrough IL_0011). Not very challenging, but it certainly demon-
strates a little bit about how IL works.
Reversing .NET 435