This article has been excerpted from book "Visual C# Programmer's Guide"
The .NET Framework Software Development Kit (SDK) installs a host of tools and utilities to help you program more efficiently. The SDK includes wrapper creation tools for interoperating with existing unmanaged code, tools that help you discover and use Web services that are based on Simple Object Access Protocol (SOAP), and tools that enable you to configure security for managed code. This section provides an overview of the Intermediate Language Disassembler (ILDASM) and other debugging tools provided with the .NET Framework.
Using ILDASM to Disassemble and Display .NET Metadata
All the languages on the .NET platform compile into MSIL and are subsequently compiled into native code at runtime by the JIT compiler. The Intermediate Language (IL) includes a very powerful feature for accessing its internal metadata called reflection. The Reflection API provided by the .NET runtime enables a programmer to discover and invoke public types of an assembly at runtime. The ILDASM tool can be used to view the metadata contained within a .NET file and to disassemble a .NET assembly or module into IL code.
Viewing the Contents of a .NET Portable Executable File
To start ILDASM, choose Run from the Start menu and type ILDASM. Once you've started the ILDASM tool, choose Open from the File menu. Navigate to the "Hello, C#" programs created earlier and select it. You should see a window similar to the one shown in Figure 4.1.
Figure 4.1: ILDASM Tool
The figure shows a couple of symbols along with some names. Table 4.1 lists all the symbols and their meanings. Once you have reviewed at them, you will understand some of the contents shown in Figure 4.1.
Table 4.1: ILDASM Symbols
To view the manifest of the assembly, double-click on the Manifest item in ILDASM. The resulting display is reproduced in Figure 4.2.
Figure 4.2: Hello, C# Class's Manifest
The manifest of a portable executable (PE) file provides some important information about the files dependencies, version, and culture. This metadata within the manifest makes every .NET PE file self-describing.
The first section of the manifest begins with .assembly extern mscorlib, indicating that the Hello class uses classes (e.g., System.Console) that are stored in the mscorlib assembly. The publickeytoken (a public key only available in cases of strong-named assemblies) and version of the mscorlib assembly are also embedded in this section of the manifest. Having this version information stored in the manifest solves some of the versioning problems otherwise encountered when different version of the same assembly is present. The .NET runtime can easily check the assembly manifest for version information and then load the correct version of the assembly.
The next section, which contains .assembly Hello, is the assembly manifest of the assembly Hello. This section is only present in assemblies, that is, modules do not have this section. The assembly manifest contains the culture, version, hash algorithm for encryption, publickeytoken, and other important metadata about the assembly. Since in this case we have not specified any special version or culture settings on the assembly, the default version of 0:0:0:0 is applied.
The section containing .module Hello.exe states that the assembly is stored within the PE file called Hello.exe. The remaining sections contain other relevant metadata used by the .NET runtime.
To explore the various contents of the assembly, click on Hello to expand and view its internal members. Figure 4.3 shows the contents of the Hello assembly.
Figure 4.3: Contents of the Assembly
From the figure we can make out that the assembly contains a single class called Hello. Double click the line that starts with .class private auto to find the definition of the Hello class, as presented in Figure 4.4. 38
Figure 4.4: Hello Class Definition
The figure shows that Hello is a private class that extends the System.Object class from the mscorlib assembly. You might remember that all classes in the .NET Framework extend the System.Object class directly or indirectly. Hence, even though the class is not explicitly extended in the source code, the C# compiler automatically extends the class from System.Object.
The next line in Figure 4.3 contains .ctor: void(), the default constructor for the class. The C# compiler automatically adds this line too, if you do not define a constructor for the class. The default constructor is always public and takes no parameters. Figure 4.5 shows the definition of the default constructor for the Hello class.
Figure 4.5: Default Constructor
The first section regarding code size indicates that the constructor occupies 7 bytes of MSIL. The .maxstack 1 section indicates that only one operand at a time can be pushed onto the virtual stack for computation. Next, the directive ldarg.0 loads the class's this pointer on the virtual stack. On line IL_0001, the System.Object class constructor (or base class constructor) is called. Finally, on line IL_0006, the method returns from the constructor.
Lastly, to examine the Main method of the class Hello, double-click the Main:: void() line from the screen shown in Figure 4.3. Perhaps you have already noticed the symbol to the left of this line that signifies the method is static.
Figure 4.6 shows the contents of the Main method.
Figure 4.6: Definition of the Main Method
You can see from the top line of the figure that Main is a private, static method that returns a void. The .entrypoint section tells the .NET runtime that this method is the entry point for the assembly and that the .NET runtime should begin executing code starting with this method. The // Code size section indicates that this method occupies 11 MSIL bytes, and the .maxstack section indicates that at a given time, a maximum of 1 byte can be loaded on the virtual stack. The line IL_0000 loads the string "Hello, C#!" on the virtual stack. (Because static methods don't have a this pointer, the variables get loaded on the stack first; otherwise, the this pointer is loaded first.) On line IL_0005, the WriteLine(string) method of the class System.Console from the mscorlib assembly is called and the string is displayed on the console. Finally, on line IL_000a, the method returns. Thus ends your brief tour of the Hello class.
Emitting IL from a .NET PE File
The ILDASM tool can also be used to emit the IL code from a .NET PE file. To decompile a file, load the file into ILDASM as indicated above and select Dump from the File menu. You are presented with a dialog box similar to that in Figure 4.7. From this dialog box, select the options you require (the default options are sufficient in most cases) and click OK.
Figure 4.7: Dump File Dialog Box
Next, you are presented with the File Save dialog box. Type an appropriate file name and click OK to save the IL code for your PE file. Two files get created when you click OK: the IL file (Hello.il) and a resource file containing resources for your assembly (Hello.res).
Now open the Hello.il file in notepad to view its contents. Within the Main method definition in this file, find the following line:
IL_0000: ldstr "Hello, C#!"
Change it to read as follows and save the file:
IL_0000: ldstr "Hello World"
Now bring up the command prompt window and navigate to the directory where you saved the Hello.il file. Run the ILASM tool (IL Assembler) to compile the IL file into a .NET PE file that contains the change you have made. Before you run the ILASM tool, be sure you have closed the ILDASM tool running on the Hello.exe file; otherwise, Hello.exe remains locked and the new file won't be generated. Issue the command ilasm hello.il to compile the IL code into a PE file. Finally, run the file Hello.exe to view the reflected changes you made in the IL (shown in Figure 4.8.).
Figure 4.8: Assembling Using ILASM Tool
Conclusion
Hope this article would have helped you in understanding tools and utilities in the .NET Framework. See my other articles on the website on .NET and C#.