Detailed Assembly Structure

This section will discuss one tool and one set of APIs that help you manipulate and view the assembly structure. This tool is shipped with the SDK in Program FilesMicrosoft Visual Studio .NETFrameworkSDKin. The tool is called ILDasm, and it is extremely useful. ILDasm has online help available under the Help menu. Documentation about the advanced features of ILDasm can be found in Program FilesMicrosoft Visual Studio .NETFrameworkSDKTool Developers Guidedocs.

To drill down into the structure of the assembly, you need to invoke ILDasm with the advanced option. Still looking at the simple HelloWorld.exe assembly, from a command prompt window, start up ILDasm as follows:

ILDasm /adv helloworld.exe

It's important to show and verify the structure of the assembly. To see the PE file format and the assembly format, select the View, COR header menu item. (If you did not invoke ILDasm with the /adv option, you will not see these menu items.) You will be presented with a window that looks like Figure 4.1.

Figure 4.1. PE header for HelloWorld.exe.


ILDasm presents the PE header for informational purposes only. This PE header is part of any PE file, not just .NET assemblies. From this figure, you can see the Import Address Table (ILDasm calls it the Import Directory) and the entry point (ILDasm calls it the Native Entry Point Address). Remember from the previous discussion that the entry point is the simple managed hook into managed code. The Import Address Table (IAT) directs the loader of the PE file to load the execution engine. Notice also that 16 directories exist, but ILDasm shows only 15 because the last entry is reserved at this point and not used with .NET assemblies.

If you scroll down a little, you will see a human-readable version of the IAT, as shown in Figure 4.2.

Figure 4.2. IAT and CLR header for HelloWorld.exe.


From Figure 4.2, you can verify that the IAT is directing the loader to load mscoree.dll. From this figure, you can see where the metadata begins (Metadata directory). To follow the previous discussion, the most important part of the header is the Entry Point Token. For this simple assembly, a strong name has not been assigned, and no resources are associated with this assembly. Therefore, the directory entries for these items are zero. The only piece of information that is needed to run this program is the entry point of the program, which is encoded in the Entry Point Token as 0x60000001. As indicated earlier, this token is a reference to index 1 of the method table. The method table is part of the metadata, which starts at the address indicated by the Metadata directory entry. To view an outline of the metadata, select the View, Metainfo, Header menu item. Doing so puts a check mark on the Header menu item indicating what you want to view. To view the table, press Ctrl+M or select the View, Metainfo, Show menu item. A new window appears that looks like Figure 4.3.

Figure 4.3. Metadata info.


The first line in Figure 4.3 shows the main set of tables that make up the metadata. These are known as heaps, stream heaps, or just streams. ILDasm shows four heaps. A fifth heap exists that is a table of tables. This heap contains all the tables that are valid for the assembly at hand. This special stream is known as the #~ stream. Table 4.1 gives an explanation of each of the streams in the metadata.

Table 4.1. Streams in .NET Metadata
Stream Description
#~ #~ contains the physical representation of the logical metadata streams.
#Strings This is a physical representation of the logical strings table. It contains names that are used by other portions of the metadata for identifiers such as Main or WriteLine so that a human-readable name can be associated with a type, value, method, or field. This heap is a byte array; therefore, indexes into this heap are offsets.
#Blob The blob heap contains most of the metadata information that is encoded in one form or another. For example, the blob heap contains signature metadata on each of the methods, type metadata about each type, parameter metadata, and so forth. This heap is a byte array; therefore, indexes into this heap are offsets.
#US This heap contains a list of the user-defined strings in an assembly. For example, with helloworld.exe, a call was made as follows:
Console.WriteLine("Hello World!");

The string “Hello World!” is part of the user-defined string heap in the hello.exe assembly. This heap is a byte array; therefore, indexes into this heap are offsets.
#GUID This heap contains a 16-byte representation of the GUIDs that this assembly uses. For most cases, this heap has only one 16-byte entry, which is the GUID for the assembly. Indexes into this table are numbered starting with 1 for the first GUID, 2 for the next, and so on.

The remaining lines in Figure 4.3 list characteristics of each of the tables that are valid for this assembly. The first column is the identifier for the table. Here you can see where the table ID of 0x6 came from for the method table. Other common tables are the Module table (0X0), the TypeDef table (0x2), and the Assembly table (0x20). The last table identifier is 0x29; therefore, approximately 41 tables exist. (Not all identifiers are used.) It would be hard to put together an assembly that used all of the tables. The simple Hello World program has eight tables. Table 4.2 provides a list of the possible tables in the metadata.

Table 4.2. Metadata Tables
Code Table Name Columns Description
0x00 Module 5 This table contains one and only one row, which describes the module, its name, and the GUID that is assigned to it.
0x01 TypeRef 3 This table contains the necessary information that is required to resolve this type (index into Module, ModuleDef, AssemblyRef, or TypeRef tables) and the name of the type (name and namespace).
0x02 TypeDef 6 This table contains one row for each type that is defined in the module. Columns describe the name of the type and namespace (index into the #Strings heap), the type from which this type is derived, the fields that are contained by this type (FieldDef), and the methods that are owned by this type (MethodDef).
0x04 Field 3 This table defines the attributes of a field (accessibility, static, and so on), its name, and its signature.
0x06 Method 6 This table has an entry for each method that is defined in the module. A column describes how to get to the code associated with the method, the name of the method (index into #String stream), flags describing the methods (accessibility, static, final, and so on), the signature of the method (return type, number and type of parameters, and so on), and a pointer to the beginning of the parameters that is associated with this method.
0x08 Param 3 This table has one entry for each parameter that is used within the module. A column describes the name, and flags indicate whether it is an [in] parameter or an [out] parameter, whether it has a default value, and whether it is optional.
0x09 InterfaceImpl 2 This table describes each of the interfaces that is described by this module. The table has columns that describe the class with which this interface is implemented and the type of the interface.
0x0A MemberRef 3 This table contains one entry for either a field or a method that is part of a class. Each row has a column that describes the signature of the member, the name of the member, and the type of the member.
0x0B Constant 3 This table stores constants for this module. Each row describes a different constant, parent, value, and type.
0x0C CustomAttribute 3 This table contains one entry for each custom attribute that is utilized in the module. Each row contains enough information to allow instantiation of the class object that is specified by the CustomAttribute. Each row contains an index into its parent table, an index into the type table, and the value of the constant.
0x0D FieldMarshal 2 This table is used by managed code that interfaces with unmanaged code. This table links an existing row in the Field or Param table to information in the Blob heap that defines how that field or parameter should be marshaled when calling to or from unmanaged code via PInvoke.
0x0E DeclSecurity 3 This table associates a security action with a permission set for a method or type.
0x0F ClassLayout 3 This table specifies a layout for a particular class. One row exists for each specialized layout. The Class Layout table specifies the packing size, class size, and parent (the class).
0x10 FieldLayout 2 This table specifies how an individual field is positioned in a class. One row exists for each special kind of field layout.
0x11 StandAloneSig 1 This table is most often used to specify initialization for local variables in method calls. It also is used to specify a signature for IL calli instructions.
0x12 EventMap 2 This table provides a mapping between a list of events and a particular class that handles the events.
0x14 Event 3 This table provides a way to associate a group of methods with a single class. For events, you will typically see add and remove methods to add or remove a delegate from a chain, respectively. The Event table combines these two methods into a single class.
0x15 PropertyMap 2 This table maps a set of properties to a particular class.
0x17 Property 3 This table, like the Event table, gathers together methods and associates them with a single class.
0x18 MethodSemantics 3 This table specifies special semantics for dealing with events and properties.
0x19 MethodImpl 3 This table has a row for each interface that is implemented. The columns specify in which class it is implemented as well as the method body and the method declaration.
0x1A ModuleRef 1 This table has a single column that is the name of the module. The name of the module must correspond to an entry in the file table so that the module can be resolved.
0x1B TypeSpec 1 This table specifies a type via the single index into the blob heap.
0x1C ImplMap 4 This table holds information about unmanaged code that can be reached with managed code with P/Invoke.
0x1D FieldRVA 2 This table keeps track of each interface that a class implements.
0x20 Assembly 6 This table records the full definition of the current assembly. Columns exist for the name of the assembly, the version, the culture, the hash algorithm, and the public key of the public/private key pair used to give this module a strong name. A column also exists for flags that has settable options for specifying a full public key or side-by-side compatibility mode.
0x21 AssemblyProcessor 1 This table should be ignored by the CLI and treated as if it were zero. It should not be part of a PE file.
0x22 AssemblyOS 3 This table contains platform OS information such as processor and version. The CLI should ignore this table and treat it as if it were zero. It should not be part of a PE file.
0x23 AssemblyRef 6 This table contains references to other assemblies. The columns for this table are in a different order, but are similar to the columns in the Assembly table.
0x24 AssemblyRefProcessor 1 This table should be ignored by the CLI and treated as if it were zero. It should not be part of a PE file. It contains the processor and an index into the AssemblyRef table.
0x25 AssemblyRefOS 4 This table contains platform OS information such as processor and version for a referenced assembly. This table should be ignored by the CLI and treated as if it were zero. It should not be part of a PE file.
0x26 File 3 Assemblies can reference other files, such as documentation and other configuration files. An assembly references another file through the .file declaration in the assembly. This table contains all of the .file entries for a given assembly or module.
0x27 ExportedType 5 Each row in the Exported Type table is generated as a result of the .class extern directive in the IL code from which this assembly was built. The .class extern directive is required to export a type from a module that is not the main manifest assembly. This is to save space; each type's metadata is already available for export from the TypeDef table.
0x28 ManifestResource 4 The rows in this table result from the .mresource directive in the assembly. This directive associates a name with some data outside of the assembly. If the resource is not part of a standalone file, then the table contains a reference to the offset into one of the modules stream heaps.
0x29 NestedClass 2 This table records which type definitions are declared inside of other type definitions. It contains references to the nested type and the enclosing type for all nesting situations.

From Figure 4.3, you can see that not all of the tables have been defined. Each row in Figure 4.3—after the initial header showing the heaps—describes a table in the assembly.

The first column is the ID of the table (possible values indicated in Table 4.2). Following the first column is the name of the table. Next, the cbRecs item indicates how many rows are in this table. The cbRec column shows how large each row is. Finally, the cbTable column indicates how many bytes are in the given table.

If you toggle the header menu item in the View→Metainfo→Header and then either select the View→Metainfo→Show Menu item or press Ctrl+M, you will see ILDasm's view of the contents of each of the tables that are valid for this assembly. A portion of the contents is shown in Figure 4.4.

Figure 4.4. Metadata table dump.


This is a long listing, so you might want to invoke ILDasm on this assembly to view the complete output. ILDasm takes some liberties as to what it displays. It does not display a separate module table or a separate method table. ILDasm incorporates the data in these tables into the output listing. You probably do not want to use this output to understand the physical representation of the tables. Rather, this output gives you a view of the tables that is easier to understand than with a strict table view.

To round off this presentation of the assembly as viewed by ILDasm, Figure 4.5 shows the statistics on this file. This option is under the View, Statistics menu of ILDasm.

Figure 4.5. Metadata statistics.


As mentioned earlier, the managed code is only a small fraction of the overall file size. Most of the file is taken up with either the PE information or the metadata. For real applications, the ratio of file size to IL code increases as each type is reused throughout the code. This statistics page gives you a rough guess at the disk overhead that is associated with a given assembly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.235.104