找回密码
 立即注册

QQ登录

只需一步,快速开始

graper

高级会员

45

主题

63

帖子

1348

积分

高级会员

积分
1348

活字格认证

[迁移] MSIL Tutorial

graper
高级会员   /  发表于:2009-12-15 09:45  /   查看:6926  /  回复:0
Post by "KevinShan",  08-16-2007, 17:18
-----------------------------------------------------


Introduction

Microsoft Intermediate Language (MSIL) is a language used as the output of a number of compilers (C#, VB, .NET, and so forth). The ILDasm (Intermediate Language Disassembler) program that ships with the .NET Framework SDK (FrameworkSDK\Bin\ildasm.exe) allows the user to see MSIL code in human-readable format. By using this utility, we can open any .NET executable file (EXE or DLL) and see MSIL code.

The ILAsm program (Intermediate Language Assembler) generates an executable file from the MSIL language. We can find this program in the WINNT\Microsoft.NET\Framework\vn.nn.nn directory.

Any Visual C++ programmer starting with .NET development is interested in what happens in the low level of the .NET Framework. Learning MSIL gives a user the chance to understand some things that are hidden from a programmer working with C# or VB.NET. Knowing MSIL gives more power to a .NET programmer. We never need to write programs in MSIL directly, but in some difficult cases it is very useful to open the MSIL code in ILDasm and see how things are done.

A MSIL reference in DOC format is available to a .NET developer and may be found in the Framework SDK directory:

FrameworkSDK\Tool Developers Guide\docs\Partition II Metadata.doc (Metadata Definition and Semantics). In this file, I found a description of all MSIL directives such as .entrypoint, .locals, and so on.
FrameworkSDK\Tool Developers Guide\docs\Partition III CIL.doc (CIL Instruction Set) contains a full list of the MSIL commands.
I also used in my work in an ILDAsm tutorial from MSDN and an excellent article in the May 2001 issue of MSDN Magazine: "ILDASM is Your New Best Friend" by John Robbins.

I think the best way to learn the language is to write some programs in it. This is a reason I decided to make several small MSIL programs. Actually, I didn't write this code—the C# compiler generated it. I made some minor changes and added a lot of notes describing how MSIL is working.

Reading the sample projects attached to this article may help a .NET programmer understand Intermediate Language and easily read MSIL code when this is necessary.

General Information
All operations in MSIL are executed on the stack. When a function is called, its parameters and local variables are allocated on the stack. Function code starting from this stack state may push some values onto the stack, make operations with these values, and pop values from the stack.

Execution of both MSIL commands and functions is done in three steps:

Push command operands or function parameters onto the stack.
Execute the MSIL command or call function. The command or function pops their operands (parameters) from the stack and pushes onto the stack result (return value).
Read result from the stack.
Steps 1 and 3 are optional. For example, the void function doesn't push a return value to the stack.

The stack contains objects of value types and references to objects of reference type. Reference type objects are kept in the heap.

MSIL commands used to push values onto the stack are called ld... (load). Commands used to pop values from the stack are called st... (store), because values are stored in variables. Therefore, we will call the push operation loading and the pop operation storing.

Sample Projects
The code attached to this article contains a number of Console Applications written in MSIL. To build them, ensure that the ILAsm program is available through the PATH. Each project is done as a Visual Studio solution. The source IL file may be opened in the VS Text Editor. The build command runs the ILAsm program, which generates an exe file in the project directory. The run command executes this file. At the end of each program, I added these lines, which can be written in C#:
  1.     Console.WriteLine("Press Enter to continue");
  2.     Console::Read();
复制代码
This is done to see the program output when it is run from Windows Explorer.

Here's a list of the included projects:

PrintString—prints the string to the console.
XequalN—assigns a value to the int variable and prints it to the console.
Operations—reads two numbers from the console; makes operations +, -, and *; and shows the result.
Array1—allocates int array, assign values to its elements; print elements and array length.
Compare—enters two numbers and prints the minimum.
Array2—fills array elements in loop and prints some elements.
Unsafe—uses unsafe pointers to access array elements.
PInvoke—calls Win32 API.
Classes—works with classes.
Exception—handles exceptions.
I suggest that you read these projects in the same order as they are described here. In the projects' descriptions given below, I explain each new MSIL command used in the program and show some code fragments.

PrintString Program
PrintString is the MSIL Hello, World application.

MSIL directives used in the code are as follows:

.entrypoint—defines the application entry point (the function called by .NET Runtime when the program starts).
.maxstack—defines the maximum stack depth used by the function code. The C# compiler sets always the exact value for each function. In the sample project, I set this value to 8.
MSIL commands are as follows:

ldstr string—loads the string constant onto the stack.
call function(parameters)—calls the static function. Parameters for the function should be loaded onto the stack before this call.
pop—pops a value from the stack. Used when we don't need to store a value in the variable.
ret—returns from a function.
Calling the static function is simple. We push to stack the function parameters, call the function, and read from the stack function return value (if function is not void). Console.WriteLine is an example of such a function.

Here is the code:
  1. .assembly PrintString {}

  2. /*
  3.     Console.WriteLine("Hello, World)"
  4. */

  5. .method static public void main() il managed
  6. {
  7.     .entrypoint             // this function is the application
  8.                             // entry point

  9.     .maxstack 8


  10.     // *****************************************************
  11.     // Console.WriteLine("Hello, World)";
  12.     // *****************************************************
  13.     ldstr "Hello, World"        // load string onto stack

  14.     // Call static System.Console.Writeline function
  15.     // (function pops string from the stack)
  16.     call   void [mscorlib]System.Console::WriteLine
  17.                                  (class System.String)


  18.     // *****************************************************
  19.     ldstr "Press Enter to continue"
  20.     call   void [mscorlib]System.Console::WriteLine
  21.                                  (class System.String)


  22.     // Call the System.Console.Read function
  23.     call int32 [mscorlib]System.Console::Read()

  24.     // The pop instruction removes the top element from the stack.
  25.     // (remove number returned by Read() function)
  26.     pop
  27.     // *****************************************************

  28.     ret
  29. }
复制代码
XequalN Program
The program assigns a value to the integer variable and prints it to the console window.

Commands:

ldc.i4.n—loads a 32-bit constant (n from 0 to 8) onto the stack
stloc.n—stores a value from the stack to local variable number n (n from 0 to 3)
Code:

  1. .assembly XequalN {}

  2. // int x;
  3. // x = 7;
  4. // Console.WriteLine(x);

  5. .method static public void main() il managed
  6. {
  7.     .entrypoint

  8.     .maxstack 8

  9.     .locals init ([0] int32 x)  // Allocate local variable

  10.     // *****************************************************
  11.     // x = 7;
  12.     // *****************************************************
  13.     ldc.i4.7                    // load constant onto stack
  14.     stloc.0                     // store value from stack to
  15.                                 // var. 0

  16.     // *****************************************************
  17.     // Console.WriteLine(x);
  18.     // *****************************************************
  19.     ldloc.0                     // load var.0 onto stack
  20.     call void [mscorlib]System.Console::WriteLine(int32)

  21.     ret
  22. }
复制代码
Operations Program
The program reads two numbers from the console, makes simple math operations with them, and shows the result.

Commands:

add—adds two values. Command parameters should be loaded onto the stack before the call. The function pops the parameters and pushes a result onto the stack.
sub—subtracts two values.
mul—multiplies two values.
Code fragments:

  1. .assembly Operations {}
  2. /*
  3. // This program works as C# code:

  4.             int x, y, z;
  5.             string s;

  6.             Console.WriteLine("Enter x:");
  7.             s = Console.ReadLine();
  8.             x = Int32.Parse(s);

  9.             Console.WriteLine("Enter y:");
  10.             s = Console.ReadLine();
  11.             y = Int32.Parse(s);

  12.             z = x + y;
  13.             Console.Write("x + y = ");
  14.             Console.Write(z);
  15.             Console.WriteLine("");

  16.             z = x - y;
  17.             Console.Write("x - y = ");
  18.             Console.Write(z);
  19.             Console.WriteLine("");

  20.             z = x * y;
  21.             Console.Write("x * y = ");
  22.             Console.Write(z);
  23.             Console.WriteLine("");
  24. */

  25. .method static public void main() il managed
  26. {
  27.     .entrypoint
  28.     .maxstack 8

  29.     .locals init ([0] int32 x,
  30.            [1] int32 y,
  31.            [2] int32 z,
  32.            [3] string s)

  33.     // *****************************************************
  34.     // Console.WriteLine("Enter x:");
  35.     // *****************************************************
  36.     ldstr      "Enter x:"       // load string onto stack
  37.     call       void [mscorlib]System.Console::WriteLine(string)

  38.     // *****************************************************
  39.     // s = Console.ReadLine();
  40.     // *****************************************************
  41.     call       string [mscorlib]System.Console::ReadLine()
  42.     stloc.3                     // store value to var. 3

  43.     // *****************************************************
  44.     // x = Int32.Parse(s);
  45.     // *****************************************************
  46.     ldloc.3                     // load variable 3 onto stack

  47.     // Call System.Int32::Parse(string)
  48.     // Function pops string from stack and pushes to stack
  49.     // int32 value - result of parsing.
  50.     call       int32 [mscorlib]System.Int32::Parse(string)

  51.     stloc.0                     // store value to var. 0



  52.     // *****************************************************
  53.     // Same operations with variable y
  54.     // *****************************************************
  55.     ldstr      "Enter y:"
  56.                // load string
  57.     call       void [mscorlib]System.Console::WriteLine(string)
  58.                // call
  59.     call       string [mscorlib]System.Console::ReadLine()
  60.                // call
  61.     stloc.3
  62.                // store to var. 3
  63.     ldloc.3
  64.                // load var. 3
  65.     call       int32 [mscorlib]System.Int32::Parse(string)
  66.                // call
  67.     stloc.1
  68.                // store to var. 1

  69.     // *****************************************************
  70.     // z = x + y;
  71.     // *****************************************************
  72.     ldloc.0             // load variable 0 onto stack
  73.     ldloc.1             // load variable 1 onto stack

  74.     // pop two values from the stack, add them and push result
  75.     // onto stack
  76.     add

  77.     stloc.2             // store to variable 2

  78.     // *****************************************************
  79.     // Console.Write("x + y = ");
  80.     // *****************************************************
  81.     ldstr      "x + y = "          // load string onto stack
  82.     call       void [mscorlib]System.Console::Write(string)

  83.     // *****************************************************
  84.     // Console.Write(z);
  85.     // *****************************************************
  86.     ldloc.2                    // load variable 2 onto stack
  87.     call       void [mscorlib]System.Console::Write(int32)

  88.     // *****************************************************
  89.     // Console.WriteLine("");
  90.     // *****************************************************
  91.     ldstr      ""                  // load string onto stack
  92.     call       void [mscorlib]System.Console::WriteLine(string)

  93.     // Same operations with subtraction and multiplication ...

  94.     ret
  95. }
复制代码
Array1 Program
The program allocates the int array, assigns values to its elements, and then prints the elements and array length.

Commands:

newarr type—creates an array of type elements. The array size should be loaded onto the stack before a call to this command. Loads onto the stack a reference to the array.
stelem.i4—assigns a value to an array member. The value has type Int32. The array reference, index, and value should be loaded onto the stack before a call to this command.
ldelema type—loads to the stack the address of an array element. The array reference and index should be loaded onto the stack before a call to this command. The address is used to call a non-static class function (see later).
ldlen—loads the length of an array onto the stack. The array reference should be loaded onto the stack before a call to this command.
ldloca.s variable—loads the address of the variable onto the stack.
ldc.i4.s value—loads an Int32 constant onto the stack (used for values more than 8).
conv.i4—converts value from the stack to Int32.
call instance function(arguments)—calls a non-static class function. Before a call to a non-static function, we need to load onto the stack the address of the class object (used first as a hidden parameter, as in C++) and function arguments. In this sample object, the address is loaded using the ldelema and ldloca commands.
In some code fragments in this sample, I wrote in the notes to stack the state starting after the last local variable. In this sample, we see the variable generated by the compiler. This variable is used to make the call to the non-static class function.

Code:

  1. .assembly Array1 {}

  2. /*
  3. // This program works as C# code:

  4. int[] x = new int[5];
  5. x[0] = 10;
  6. x[1] = 20;

  7. Console.WriteLine("x[0] = " + x[0].ToString());
  8. Console.WriteLine("x[1] = " + x[1].ToString());

  9. Console.WriteLine("Array length = " + x.Length.ToString());

  10. */

  11. .method static public void main() il managed
  12. {
  13.     .entrypoint
  14.     .maxstack 8

  15.     .locals init ([0] int32[] x,
  16.                   [1] int32 tmp)    // generated by compiler


  17.     // *****************************************************
  18.     // x = new int[5];
  19.     // *****************************************************
  20.     ldc.i4.5                     // load constant onto stack

  21.     // create array and store reference onto stack
  22.     newarr     [mscorlib]System.Int32

  23.     // Store (pop) value from the stack and place it to local
  24.     // variable 0.
  25.     stloc.0

  26.     // *****************************************************
  27.     // x[0] = 10;
  28.     // *****************************************************
  29.     ldloc.0           // Load local variable 0 onto stack (array)
  30.     ldc.i4.0          // Load constant 0 to the stack     (index)
  31.     ldc.i4.s   10     // Load constant 10 to the stack    (value)
  32.     stelem.i4         // array[index] = value


  33.     // The same operations with element number 1...


  34.     // ***************************************************
  35.     // Console.WriteLine("x[0] = " + x[0].ToString());
  36.     // ***************************************************
  37.     ldstr      "x[0] = "            // load string onto stack
  38.                 // STACK: "x[0] = "  (stack is shown from local
  39.                 // variables)
  40.     ldloc.0                         // load variable 0 onto stack
  41.     ldc.i4.0                        // load constant 0 onto stack
  42.                 // STACK: "x[0] = " -> x -> 0
  43.     // Load address of array element onto stack.
  44.     ldelema    [mscorlib]System.Int32
  45.                 // STACK: "x[0] = " -> pointer to Int32 instance
  46.                 // 10
  47.     // Call non-static function System.Int32::ToString().
  48.     call       instance string [mscorlib]System.Int32::ToString()
  49.                 // STACK: "x[0] = " -> "10"
  50.     // call static System.String::Concat(string, string)
  51.     call       string [mscorlib]System.String::Concat
  52.                                                (string, string)
  53.                 // STACK: "x[0] = 10"
  54.     // call static System.Console::WriteLine(string)
  55.     call       void [mscorlib]System.Console::WriteLine(string)
  56.                 // STACK: empty


  57.     // The same operations with element number 1 ...


  58.     // *****************************************************
  59.     // Console.WriteLine("Array length = " + x.Length.ToString());
  60.     // *****************************************************
  61.     ldstr      "Array length = "
  62.                 // load string onto stack
  63.                 // STACK: "Array length = "
  64.     ldloc.0
  65.                 // load variable 0 to stack
  66.                 // STACK: "Array length = " -> x
  67.     ldlen
  68.                 // push the length of array onto stack
  69.                 // STACK: "Array length = " -> 5
  70.     conv.i4
  71.                 // Convert to int32, pushing int32 onto stack
  72.                 // STACK: "Array length = " -> 5
  73.     stloc.1
  74.                 // store to local variable 1 (tmp)
  75.                 // STACK: "Array length = "
  76.     ldloca.s   tmp
  77.                 // load address of variable tmp onto stack
  78.                 // STACK: "Array length = " -> &tmp
  79.     call       instance string [mscorlib]System.Int32::ToString()
  80.                 // STACK: "Array length = " -> "5"
  81.     call       string [mscorlib]System.String::Concat
  82.                                        (string, string)
  83.                 // STACK: "Array length = 5"
  84.     call       void [mscorlib]System.Console::WriteLine(string)
  85.                 // STACK: empty

  86.     ret
  87. }
复制代码
Compare Program
The program reads two numbers and prints their minimum.

Commands:

bge.s label—goes to label if value1 is greater than or equal to value 2. Values 1 and 2 should be loaded onto the stack before a call to this command.
br.s label—goes to label.
box value type—converts a value type to an Object and loads the Object's reference onto the stack.
Boxing in this program is caused by the C# line: Console.WriteLine("{0:d}", z);
Writing this line in this way: Console.WriteLine(z.ToString());
doesn't cause boxing.

Code:
  1. .assembly Compare {}
  2. /*
  3.             int x, y, z;
  4.             string s;

  5.             Console.WriteLine("Enter x:");
  6.             s = Console.ReadLine();
  7.             x = Int32.Parse(s);

  8.             Console.WriteLine("Enter y:");
  9.             s = Console.ReadLine();
  10.             y = Int32.Parse(s);

  11.             if ( x < y )
  12.                 z = x;
  13.             else
  14.                 z = y;

  15.             Console.WriteLine("{0:d}", z);
  16. */

  17. .method static public void main() il managed
  18. {
  19.     .entrypoint
  20.     .maxstack 8

  21.     .locals init ([0] int32 x,
  22.                   [1] int32 y,
  23.                   [2] int32 z,
  24.                   [3] string s)

  25.     // *****************************************************
  26.     // Console.WriteLine("Enter x:");
  27.     // *****************************************************
  28.     ldstr      "Enter x:"               // load string onto stack
  29.     call  void [mscorlib]System.Console::WriteLine(string)

  30.     // *****************************************************
  31.     // s = Console.ReadLine();
  32.     // *****************************************************
  33.     call       string [mscorlib]System.Console::ReadLine()
  34.     stloc.3                             // store to var. 3

  35.     // *****************************************************
  36.     // x = Int32.Parse(s);
  37.     // *****************************************************
  38.     ldloc.3                             // load var. 3 onto stack
  39.     call       int32 [mscorlib]System.Int32::Parse(string)
  40.     stloc.0                             // store to var. 0

  41.     // The same operations for y ...

  42.     // *****************************************************
  43.     // branch
  44.     // if ( x >= y ) goto L_GR;
  45.     // *****************************************************
  46.     ldloc.0                     // load x onto stack (value 1)
  47.     ldloc.1                     // load y onto stack (value 2)
  48.     bge.s  L_GR                 // goto L_GR if value1 is greater
  49.                                 // than or equal to value2

  50.     // *****************************************************
  51.     // z = x
  52.     // *****************************************************
  53.     ldloc.0                     // load variable 0 onto stack
  54.     stloc.2                     // store to variable 2

  55.     br.s       L_CONTINUE       // goto L_CONTINUE

  56. L_GR:

  57.     // *****************************************************
  58.     // z = y
  59.     // *****************************************************
  60.     ldloc.1             // load variable 1 onto stack
  61.     stloc.2             // store to variable 2

  62. L_CONTINUE:

  63.     // *****************************************************
  64.     // Console.WriteLine("{0:d}", z);
  65.     // NOTE: this line causes boxing.
  66.     // *****************************************************
  67.     ldstr      "{0:d}"  // load string onto stack
  68.     ldloc.2             // load variable 2 to stack (z)
  69.     box       [mscorlib]System.Int32   // convert Int32 to Object
  70.     call  void [mscorlib]System.Console::WriteLine(string, object)

  71.     ret
  72. }
复制代码
Array2 Program
The program fills an array in the loop and prints its elements. This time, we add the static function ShowNumber(int), which is called from main.

Commands:

blt.s label—goes to label if value 1 is less than value 2. Values 1 and 2 should be loaded onto the stack before a call to this command.
ldelem.i4—loads an array element onto the stack. A reference to the array and index should be loaded onto the stack before a call to this command.
ldarga.s argument—loads the address of the function argument onto the stack.
We can see in this program that the for loop is implemented in MSIL using labels.

Code:
  1. .assembly Array2 {}
  2. /*

  3.             int[] px = new int[100];
  4.             int i;

  5.             for ( i = 1; i < 100; i++ )
  6.             {
  7.                 px = i + 1;
  8.             }

  9.             ShowNumber(px[5]);
  10.             ShowNumber(px[10]);


  11.         static void ShowNumber(int n)
  12.         {
  13.             Console.WriteLine(n.ToString());
  14.         }
  15. */

  16. .method static public void main() il managed
  17. {
  18.     .entrypoint
  19.     .maxstack 8

  20.     .locals init ([0] int32[] px,
  21.                   [1] int32 i)

  22.     // *****************************************************
  23.     // x = new int[100]
  24.     // *****************************************************
  25.     ldc.i4.s   100                      // load constant onto
  26.                                         // stack
  27.     newarr     [mscorlib]System.Int32   // allocate Int32
  28.     stloc.0                             // store to variable 0

  29.     // *****************************************************
  30.     // i = 1
  31.     // *****************************************************
  32.     ldc.i4.1                    // load constant onto stack
  33.     stloc.1                     // store to variable 1

  34.     br.s       CHECK_COUNTER    // goto CHECK_COUNTER

  35. START_LOOP:
  36.     // *****************************************************
  37.     // px = i + 1;
  38.     // *****************************************************
  39.     ldloc.0                     // load variable 0 to stack
  40.                                 // STACK: px
  41.     ldloc.1                     // load variable 1 to stack
  42.                                 // STACK; px -> i
  43.     ldloc.1                     // load variable 1 to stack
  44.                                 // STACK: px -> i -> i
  45.     ldc.i4.1                    // load constant to stack
  46.                                 // STACK: px -> i -> i -> 1.
  47.     add                         // add last two values
  48.                                 // STACK: px -> i -> i+1
  49.                                 //        (array,index,value)
  50.     stelem.i4                   // store value to array element:
  51.                                 // array[index] = value
  52.                                 // STACK: empty
  53.     // *****************************************************
  54.     // i = i + 1
  55.     // *****************************************************
  56.     ldloc.1                     // load variable 1 onto stack
  57.     ldc.i4.1                    // load constant onto stack
  58.     add                         // add
  59.     stloc.1                     // store to variable 1

  60. CHECK_COUNTER:
  61.     // *****************************************************
  62.     // if i < 100 goto start f loop
  63.     // *****************************************************
  64.     ldloc.1                     // load variable 1 onto stack
  65.     ldc.i4.s   100              // load constant onto stack
  66.     blt.s      START_LOOP       // if value1 < value2 go to
  67.                                 // START_LOOP


  68.     // *****************************************************
  69.     // ShowNumber(px[5]
  70.     // *****************************************************
  71.     ldloc.0                     // load variable 0 onto stack
  72.                                 // (array)
  73.     ldc.i4.5                    // load constant onto stack
  74.                                 // (index)
  75.     ldelem.i4                   // load array element to stack
  76.     call       void ShowNumber(int32)   // call ShowNumber

  77.     // *****************************************************
  78.     // ShowNumber(px[10]
  79.     // *****************************************************
  80.     ldloc.0
  81.     ldc.i4.s   10
  82.     ldelem.i4
  83.     call       void ShowNumber(int32)

  84.     ret
  85. }

  86. .method static public void  ShowNumber(int32 n) il managed
  87. {
  88.   .maxstack  1

  89.   ldarga.s   n          // load to stack address of argument n

  90.   call       instance string [mscorlib]System.Int32::ToString()
  91.   call       void [mscorlib]System.Console::WriteLine(string)

  92.   ret
  93. }
复制代码
Unsafe Program
The program fills and prints the int array using an unsafe pointer.

In this program, we see the new, unsafe types: int32* and int32&amp;. The pinned keyword, used with a local variable, prevents GC from moving the object pointed to by the variable.

Commands:

dup—duplicates the value on the stack.
stind.i4—stores the value by address. The address and value should be loaded onto the stack before a call to this command.
Code:
  1. .assembly Unsafe {}
  2. /*
  3. int[] nArray = new int[5];
  4. int i;
  5. int* pCurrent;

  6. fixed ( int* pArray = nArray )
  7. {
  8.     pCurrent = pArray;

  9.     for ( i = 0; i < 5; i++ )
  10.     {
  11.         *pCurrent++ = i + 1;
  12.     }
  13. }

  14. for ( i = 0; i < 5; i++ )
  15. {
  16.     Console.WriteLine(nArray.ToString());
  17. }

  18. */

  19. .method static public void main() il managed
  20. {
  21.     .entrypoint
  22.     .maxstack 8

  23.     .locals ([0] int32[] nArray,
  24.              [1] int32 i,
  25.              [2] int32* pCurrent,
  26.              [3] int32&amp; pinned pArray)  // GC doesn't move
  27.                                         // pointed object

  28.     // *****************************************************
  29.     // nArray = new int[5];
  30.     // *****************************************************
  31.     ldc.i4.5                            // load constant 5 onto
  32.                                         // stack
  33.     newarr     [mscorlib]System.Int32   // create array Int32[5]
  34.     stloc.0                             // store value from stack
  35.                                         // to local var. o

  36.     // *****************************************************
  37.     // pArray = nArray    (pArray = &amp;nArray[0])
  38.     // *****************************************************
  39.     ldloc.0
  40.                // load variable 0 onto stack (array)
  41.     ldc.i4.0
  42.                // load constant 0 onto stack (index)
  43.     ldelema    [mscorlib]System.Int32
  44.                // load address of array[index] to stack
  45.     stloc.3
  46.                // store value from stack to local var. 3

  47.     // *****************************************************
  48.     // pCurrent = pArray;
  49.     // *****************************************************
  50.     ldloc.3                     // load variable 3 onto stack
  51.     conv.i                      // convert to native int
  52.     stloc.2                     // store to variable 2

  53.     // *****************************************************
  54.     // i = 0
  55.     // *****************************************************
  56.     ldc.i4.0                    // load constant 0 onto stack
  57.     stloc.1                     // store value to var. 1

  58.     // *****************************************************
  59.     // goto CHECK_COUNTER
  60.     // *****************************************************
  61.     br.s       CHECK_COUNTER

  62. START_LOOP:

  63.     // *****************************************************
  64.     // *pCurrent++ = i + 1                            [STACK]
  65.     // *****************************************************
  66.     // 1) keep old pCurrent value on the stack and increment
  67.     // pCurrent
  68.     ldloc.2
  69.           // load variable 2 onto stack     [pCurrent]
  70.     dup
  71.           // duplicate the top value of the stack
  72.           //                                [pCurrent pCurrent]
  73.     ldc.i4.4
  74.           // load constant 4 onto stack     [pCurrent pCurrent 4]
  75.     add
  76.           // add                            [pCurrent pCurrent + 4]
  77.     stloc.2
  78.           // store from stack to variable 2 [pCurrent]

  79.     // 2) write (i+1) by old pCurrent value kept on the stack
  80.     ldloc.1
  81.           // load variable 1 onto stack     [pCurrent i]
  82.     ldc.i4.1
  83.           // load constant 1 onto stack     [pCurrent i 1]
  84.     add   // add                            [pCurrent i+1]
  85.     //                                      address  value
  86.     stind.i4
  87.           // store value by address         [empty]

  88.     // *****************************************************
  89.     // i = i + 1
  90.     // *****************************************************
  91.     ldloc.1             // load variable 1 onto stack
  92.     ldc.i4.1            // load constant 1 onto stack
  93.     add                 // add
  94.     stloc.1             // store to variable 1

  95. CHECK_COUNTER:

  96.     // *****************************************************
  97.     // if (i < 5) goto START_LOOP;
  98.     // *****************************************************
  99.     ldloc.1                     // load variable 1 onto stack
  100.     ldc.i4.5                    // load constant 5 onto stack
  101.     blt.s      START_LOOP       // goto if less

  102.     // *****************************************************
  103.     // pArray = 0               fixed block finished
  104.     // *****************************************************
  105.     ldc.i4.0                    // load constant 0 to stack
  106.     conv.u                      // convert to native unsigned int,
  107.                                 // pushing native int on stack
  108.     stloc.3                     // store in variable 3

  109.     // print array elements to console...

  110.     ret
  111. }
复制代码
PInvoke Program
The program shows the computer name using the Win32 API GetComputerName and MessageBox. API declarations in MSIL look like this:
  1. .method public hidebysig static pinvokeimpl("kernel32.dll"
  2.                                              autochar winapi)
  3.         int32  GetComputerName(
  4.                class [mscorlib]System.Text.StringBuilder
  5.                                       marshal( lptstr) buffer,
  6.                int32&amp; size) cil managed preservesig
  7. {
  8. }

  9. .method public hidebysig static pinvokeimpl("User32.dll"
  10.                                              autochar winapi)
  11.         int32  MessageBox(native int hWnd,
  12.                           string  marshal( lptstr) lpText,
  13.                           string  marshal( lptstr) lpCaption,
  14.                           int32 uType) cil managed preservesig
  15. {
  16. }
复制代码
They are called by the same rules as other any functions.

Classes Program
In previous programs, we called the class functions from the static function main. In this program, we will see how to write classes. The program contains two classes: Class1, with function main; and SampleClass, created in main.

Directive:

.field—defines class member. Used with keywords public, private, static, and so forth.
Commands:

stsfld static field—replaces the value of the static field with the value from the the stack.
ldfld field—loads a non-static class field onto the stack. The address of the class instance should be loaded onto the stack before a call to this command.
ldarg.n—loads argument number n onto the stack. In a non-static class function, argument 0 is a hidden argument and points to the this instance.
newobj constructor—creates a new instance of a class using constructor. Constructor parameters should be loaded onto the stack before this call. A reference to the created instance is loaded onto the stack.
callvirt instance function—calls a late-bound method on an object.
Code:
  1. .assembly Classes {}
  2. /*
  3.     class SampleClass
  4.     {
  5.         private int m_n;
  6.         private string m_s;

  7.         public static int nStatic = 10;

  8.         public SampleClass(int n, string s)
  9.         {
  10.             m_n = n;
  11.             m_s = s;
  12.         }

  13.         public int Number
  14.         {
  15.             get
  16.             {
  17.                 return m_n;
  18.             }
  19.         }

  20.         public string String
  21.         {
  22.             get
  23.             {
  24.                 return m_s;
  25.             }
  26.         }

  27.     };

  28.     class Class1
  29.     {
  30.         [STAThread]
  31.         static void Main(string[] args)
  32.         {
  33.             SampleClass o = new SampleClass(1, "Sample");

  34.             Console.WriteLine(SampleClass.nStatic.ToString());

  35.             Console.WriteLine(o.Number.ToString());

  36.             Console.WriteLine(o.String);
  37.         }
  38.     }
  39. */


  40. .class private auto ansi beforefieldinit SampleClass
  41.        extends [mscorlib]System.Object
  42. {
  43.     .field private int32 m_n              // private int m_n;
  44.     .field private string m_s             // private string m_s;
  45.     .field public static int32 nStatic    // public static int
  46.                                           // nStatic;

  47.     // private static constructor generated by compiler
  48.     // (generated to initialize static class member)
  49.     .method private hidebysig specialname rtspecialname static
  50.         void  .cctor() cil managed
  51.     {
  52.         .maxstack  8

  53.         // *************************************************
  54.         // nStatic = 10
  55.         // *************************************************
  56.         ldc.i4.s 10            // load constant onto stack
  57.         // The stsfld instruction replaces the value of a static
  58.         // field with a value from the stack
  59.         stsfld     int32 SampleClass::nStatic

  60.         ret
  61.     }

  62.     // constructor
  63.     // public SampleClass(int n, string s)
  64.     //
  65.     .method public hidebysig specialname rtspecialname
  66.         instance void  .ctor(int32 n, string s) cil managed
  67.     {
  68.         .maxstack  8

  69.         // *************************************************
  70.         // Call base class constructor
  71.         // *************************************************
  72.         ldarg.0         // Load argument 0 onto stack (hidden
  73.                         // pointer to this)
  74.         // call Object constructor
  75.         call       instance void [mscorlib]System.Object::.ctor()

  76.         // *************************************************
  77.         // m_n = n
  78.         // *************************************************
  79.         ldarg.0         // Load argument 0 onto stack
  80.                         // (hidden pointer to this)
  81.         ldarg.1         // load argument 1 onto stack (n)
  82.         // store value n in field m_n in instance pointed
  83.         // by this
  84.         stfld      int32 SampleClass::m_n

  85.         // *************************************************
  86.         // m_s = s
  87.         // *************************************************
  88.         ldarg.0         // Load argument 0 onto stack
  89.                         // (hidden pointer to this)
  90.         ldarg.2         // load argument 1 onto stack (s)
  91.         // store value s in field m_s in instance pointed
  92.         // by this
  93.         stfld      string SampleClass::m_s

  94.         ret
  95.     }

  96.     // Number property
  97.     .property instance int32 Number()
  98.     {
  99.         // call get_Number
  100.         .get instance int32 SampleClass::get_Number()
  101.     }

  102.     .method public hidebysig specialname instance int32
  103.         get_Number() cil managed
  104.     {
  105.         .maxstack  8

  106.         // variable generated by compiler
  107.         .locals ([0] int32 tmp)

  108.         // *************************************************
  109.         // return m_n;
  110.         // *************************************************
  111.         ldarg.0
  112.                   // load argument 0 (this pointer)
  113.         ldfld      int32 SampleClass::m_n
  114.                   // load field of object pointed by stack value
  115.         stloc.0
  116.                   // store in variable 0
  117.         ldloc.0
  118.                   // load variable 0 onto stack (return value
  119.                   // of function)

  120.         ret
  121.     }

  122.     // String property
  123.     .property instance string String()
  124.     {
  125.         .get instance string SampleClass::get_String()
  126.     }

  127.     .method public hidebysig specialname instance string
  128.             get_String() cil managed
  129.     {
  130.         .maxstack  8

  131.         // variable generated by compiler
  132.         .locals ([0] string tmp)

  133.         ldarg.0
  134.              // load argument 0 (this pointer)
  135.         ldfld      string SampleClass::m_s
  136.              // load field of object pointed by stack value
  137.         stloc.0
  138.              // store in variable 0
  139.         ldloc.0
  140.              // load variable 0 onto stack (return value
  141.              // of function)
  142.         ret
  143.     }
  144. }


  145. .class private auto ansi beforefieldinit Class1
  146.        extends [mscorlib]System.Object
  147. {
  148.     // public default constructor
  149.     .method public hidebysig specialname rtspecialname
  150.         instance void  .ctor() cil managed
  151.     {
  152.         .maxstack  8

  153.         // *************************************************
  154.         // Call base class constructor
  155.         // *************************************************
  156.         ldarg.0
  157.                           // load this pointer
  158.         call       instance void [mscorlib]System.Object::.ctor()
  159.                           // call Object constructor

  160.         ret
  161.     }

  162.     // Main function
  163.     .method private hidebysig static void  Main(string[] args)
  164.             cil managed
  165.     {
  166.         // this method is the entry point to the application
  167.         .entrypoint

  168.         // Custom attribute
  169.         .custom instance void [mscorlib]System.
  170.                 STAThreadAttribute::.ctor() = ( 01 00 00 00 )

  171.         .maxstack  8

  172.         .locals ([0] class SampleClass o,
  173.                  [1] int32 tmp)          // generated by compiler

  174.         // *************************************************
  175.         // o = new SampleClass(1, "Sample");
  176.         // *************************************************
  177.         ldc.i4.1                        // load constant 1 onto
  178.                                         // stack
  179.         ldstr      "Sample"             // load string constant
  180.                                         // onto stack
  181.         // create new object SampleClass passing 2 parameters
  182.         // from stack.
  183.         // Load reference to created object onto stack
  184.         newobj     instance void SampleClass::.ctor(int32, string)
  185.         stloc.0                         // store to variable 0

  186.         // *************************************************
  187.         // Access static class member
  188.         // Console.WriteLine(SampleClass.nStatic.ToString());
  189.         // *************************************************

  190.         // Load the address of the static field on the stack
  191.         ldsflda    int32 SampleClass::nStatic
  192.         // call Int32::ToString for object from stack
  193.         call       instance string [mscorlib]System.Int32
  194.                             ::ToString()
  195.         // call static WriteLine passing string from stack
  196.         // as parameter
  197.         call       void [mscorlib]System.Console
  198.                    ::WriteLine(string)

  199.         // *************************************************
  200.         // Call non-static class function
  201.         // Console.WriteLine(o.Number.ToString());
  202.         // *************************************************
  203.         ldloc.0                 // load variable 0
  204.         // call function for object from stack
  205.         call   instance int32 SampleClass::get_Number()
  206.         stloc.1                         // store to variable 1
  207.         ldloca.s  tmp                   // load address to stack
  208.         call       instance string [mscorlib]System.Int32
  209.                             ::ToString()
  210.         call       void [mscorlib]System.Console
  211.                         ::WriteLine(string)

  212.         // *************************************************
  213.         // Call non-static class member
  214.         // Console.WriteLine(o.String);
  215.         // *************************************************
  216.         ldloc.0
  217.         callvirt   instance string SampleClass::get_String()
  218.         call       void [mscorlib]System.Console
  219.                         ::WriteLine(string)

  220.         // *************************************************
  221.         ldstr "Press Enter to continue"
  222.         call   void [mscorlib]System.Console
  223.                     ::WriteLine(class System.String)
  224.         call int32 [mscorlib]System.Console::Read()
  225.         pop
  226.         // *************************************************

  227.         ret
  228.     }
  229. }
复制代码
Exception Program
The program divides two numbers, catching a divide-by-zero exception. The try/catch block in MSIL looks like it does in C#.

Command:

leave.s label—leaves a protected block such as try or catch.
Code:

  1. .assembly Exception {}

  2. /*
  3.             int x, y, z;
  4.             string s;

  5.             Console.WriteLine("Enter x:");
  6.             s = Console.ReadLine();
  7.             x = Int32.Parse(s);

  8.             Console.WriteLine("Enter y:");
  9.             s = Console.ReadLine();
  10.             y = Int32.Parse(s);

  11.             try
  12.             {
  13.                 z = x / y;

  14.                 Console.WriteLine(z.ToString());
  15.             }
  16.             catch (Exception e)
  17.             {
  18.                 Console.WriteLine(e.Message);
  19.             }

  20. */

  21. .method static public void main() il managed
  22. {
  23.     .entrypoint
  24.     .maxstack 8

  25.     .locals ([0] int32 x,
  26.              [1] int32 y,
  27.              [2] int32 z,
  28.              [3] string s,
  29.              [4] class [mscorlib]System.Exception e)

  30.     // Enter x, y ...

  31.     .try
  32.     {
  33.         // *************************************************
  34.         // z = x / y;
  35.         // *************************************************
  36.         ldloc.0                 // load var. 0
  37.         ldloc.1                 // load var. 1
  38.         div                     // divide
  39.         stloc.2                 // store in var. 2

  40.         // *************************************************
  41.         // Console.WriteLine(z.ToString());
  42.         // *************************************************
  43.         ldloca.s   z            // load address of z
  44.         call       instance string [mscorlib]System.Int32
  45.                                    ::ToString()
  46.         call       void [mscorlib]System.Console
  47.                                    ::WriteLine(string)

  48.         leave.s    END_TRY_CATCH        // exit try block
  49.     }
  50.     catch [mscorlib]System.Exception
  51.     {
  52.         stloc.s    e        // store exception thrown on
  53.                             // the stack

  54.         // *************************************************
  55.         // Console.WriteLine(e.Message);
  56.         // *************************************************
  57.         ldloc.s    e                // load e
  58.         callvirt   instance string [mscorlib]System.Exception
  59.                                    ::get_Message()
  60.         call       void [mscorlib]System.Console
  61.                                    ::WriteLine(string)
  62.         leave.s    END_TRY_CATCH        // exit catch block
  63.     }

  64.     END_TRY_CATCH:

  65.     ret
  66. }
复制代码
Downloads

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部