6 Assemblies, Manifests, and Modules


Assemblies and modules are grouping constructs, each playing a different role in the CLI.

An assembly is a set of one or more files deployed as a unit. An assembly always contains a manifest that specifies (see Partition II, section 6.1):

  • Version, name, culture, and security requirements for the assembly.

  • Which other files, if any, belong to the assembly, along with a cryptographic hash of each file. The manifest itself resides in the metadata part of a file, and that file is always part of the assembly.

  • Which of the types defined in other files of the assembly are to be exported from the assembly. Types defined in the same file as the manifest are exported based on attributes of the type itself.

  • Optionally, a digital signature for the manifest itself and the public key used to compute it.

A module is a single file containing executable content in the format specified here. If the module contains a manifest, then it also specifies the modules (including itself) that constitute the assembly. An assembly shall contain only one manifest among all its constituent files. For an assembly to be executed (rather than dynamically loaded) the manifest shall reside in the module that contains the entry point.

While some programming languages introduce the concept of a namespace, there is no support in the CLI for this concept. Type names are always specified by their full name relative to the assembly in which they are defined.

ANNOTATION

The CLI uses the term "namespace" simply to define a way to organize classes in the class library. It also allows some compression of the space required to store names. The metadata encodes names in two parts:

namespace. name

and the namespace string does not need to be duplicated for each name. There is no internal support in the CLI other than that, and there are no operations on a namespace. That is what is meant by the phrase in the last paragraph, ". . . there is no support in the CLI for this concept."


6.1 Overview of Modules, Assemblies, and Files

This section contains informative text only.


Figure 3-2 should clarify the various forms of references.

Figure 3-2. References

graphics/03fig02.gif

Eight files are shown in the picture. The name of each file is shown below the file. Files that declare a module have an additional border around them and have names beginning with "M." The other two files have a name beginning with "F." These files may be resource files, like bitmaps, or other files that do not contain CIL code.

Files M1 and M4 declare an assembly in addition to the module declaration namely, assemblies A and B, respectively. The assembly declaration in M1 and M4 references other modules, shown with straight lines. Assembly A references M2 and M3. Assembly B references M3 and M5. Thus, both assemblies reference M3.

Usually, a module belongs only to one assembly, but it is possible to share it across assemblies. When assembly A is loaded at runtime, an instance of M3 will be loaded for it. When assembly B is loaded into the same application domain, possibly simultaneously with assembly A, M3 will be shared for both assemblies. Both assemblies also reference F2, for which similar rules apply.

The module M2 references F1, shown by dotted lines. As a consequence, F1 will be loaded as part of assembly A when A is executed. Thus, the file reference shall also appear with the assembly declaration. Similarly, M5 references another module, M6, which becomes part of B when B is executed. It follows that assembly B shall also have a module reference to M6.

End informative text


6.2 Defining an Assembly

ANNOTATION

It is worth emphasizing that the notion of an assembly is just a manifest plus the modules that it specifies, including the module in which the manifest resides. The manifest can be in a separate module but is typically in the main module. The discussion here describes how you would create a manifest in ilasm using the .assembly and other directives.


An assembly is specified as a module that contains a manifest in the metadata; see Partition II, section 21.2. The information for the manifest is created from the following portions of the grammar:

<decl> ::=

Section in Partition II

 

.assembly <dottedname> { <asmDecl>* }

6.2

| .assembly extern <dottedname> { <asmRefDecl>* }

6.3

| .corflags <int32>

6.2

 | .file [nometadata] <filename> .hash = ( <bytes> )         [.entrypoint ] 

6.2.3

| .module extern <filename>

6.5

 | .mresource [public | private] <dottedname>             [( <QSTRING> )] { <manResDecl>* } 

6.2.2

| .subsystem <int32>

6.2

| ...

 

The .assembly directive declares the manifest and specifies to which assembly the current module belongs. A module shall contain at most one .assembly directive. The <dottedname> specifies the name of the assembly.

NOTE

Since some platforms treat names in a case-insensitive manner, two assemblies that have names that differ only in case should not be declared.


ANNOTATION

The identity of the assembly is important because that is what distinguishes it from other assemblies. It is not just the <dottedname> that it is given, but also a version number, language, and a public key, along with its security permissions. While it is possible to put in 0 instead of a public key, there is the possibility of name collisions, particularly if the assembly is to be made widely available. When a public key is specified, it is called "strong-named." Although the standard specifies the information that can be put into the name, it does not specify how that information should be evaluated. For example, it is up to the developer of a VES to determine what to do when the version requested is not available.


The .corflags directive sets a field in the CLI header of the output PE file [the COMIMAGE_FLAGS_ILONLY flag] (see Partition II, section 24.3.3.1). A conforming implementation of the CLI shall expect it to be 1. For backward compatibility, the three least significant bits are reserved. Future versions of this standard may provide definitions for values between 8 and 65,535. Experimental and non-standard uses should thus use values greater than 65,535.

The .subsystem directive is used only when the assembly is directly executed (as opposed to used as a library for another program). It specifies the kind of application environment required for the program, by storing the specified value in the PE file header (see Partition II, section 24.2.2). While a full 32-bit integer may be supplied, a conforming implementation of the CLI need only respect two possible values:

If the value is 2, the program should be run using whatever conventions are appropriate for an application that has a graphical user interface.

If the value is 3, the program should be run using whatever conventions are appropriate for an application that has a direct console attached.

ANNOTATION

Implementation-Specific (Microsoft):

 
 <decl> ::= ... | .file alignment <int32> | .imagebase <int64> 

The .file alignment directive sets the file alignment field in the PE header of the output file. Legal values are multiples of 512. (Different sections of the PE file are aligned, on disk, at the specified value (in bytes).)

The .imagebase directive sets the imagebase field in the PE header of the output file. This value specifies the virtual address at which this PE file will be loaded into the process.

See Partition II, section 24.2.3.2.


 
 Example (informative): .assembly CountDown { .hash algorithm 32772   .ver 1:0:0:0 } .file Counter.dll .hash = (BA D9 7D 77 31 1C 85 4C 26 9C 49 E7 02 BE E7 52 3A CB 17 AF) 
6.2.1 Information about the Assembly (<asmDecl>)

The following grammar shows the information that can be specified about an assembly.

<asmDecl> ::=

Description

Section in Partition II

 

.custom <customDecl>

Custom attributes

20

 

.hash algorithm <int32>

Hash algorithm used in the .file directive

6.2.1.1

| .culture <QSTRING>

Culture for which this assembly is built

6.2.1.2

| .publickey = ( <bytes> )

The originator's public key

6.2.1.3

| .ver <int32> : <int32> : <int32> : <int32>

Major version, minor version, revision, and build

6.2.1.4

| <securityDecl>

Permissions needed, desired, or prohibited

19

6.2.1.1 Hash Algorithm

<asmDecl> ::= .hash algorithm <int32> | ...

When an assembly consists of more than one file (see Partition II, section 6.2.3), the manifest for the assembly specifies both the name of the file and the cryptographic hash of the contents of the file. The algorithm used to compute the hash can be specified, and shall be the same for all files included in the assembly. All values are reserved for future use, and conforming implementations of the CLI shall use the SHA1 hash function and shall specify this algorithm by using a value of 32772 (0x8004).

RATIONALE

SHA1 was chosen as the best widely available technology at the time of standardization (see Partition I). A single algorithm is chosen, since all conforming implementations of the CLI would be required to implement all algorithms to ensure portability of executable images.


6.2.1.2 Culture

<asmDecl> ::= .culture <QSTRING> | ...

When present, this indicates that the assembly has been customized for a specific culture. The strings that shall be used here are those specified in the .NET Framework Standard Library Annotated Reference as acceptable with the class System.Globalization. CultureInfo. When used for comparison between an assembly reference and an assembly definition, these strings shall be compared in a case-insensitive manner.

ANNOTATION

Implementation-Specific (Microsoft): The product version of ilasm and ildasm use .locale rather than .culture.


NOTE

The culture names follow the IETF RFC1766 names. The format is "<language>-<country/region>", where <language> is a lowercase two-letter code in ISO 639-1. <country/region> is an uppercase two-letter code in ISO 3166.


6.2.1.3 Originator's Public Key

<asmDecl> ::= .publickey = ( <bytes> ) | ...

The CLI metadata allows the producer of an assembly to compute a cryptographic hash of the assembly (using the SHA1 hash function) and then encrypt it using the RSA algorithm and a public/private key pair of the producer's choosing. The results of this (an "SHA1/RSA digital signature") can then be stored in the metadata along with the public part of the key pair required by the RSA algorithm. The .publickey directive is used to specify the public key that was used to compute the signature. To calculate the hash, the signature is zeroed, the hash calculated, then the result stored into the signature.

A reference to an assembly (see Partition II, section 6.3) captures some of this information at compile time. At runtime, the information contained in the assembly reference can be combined with the information from the manifest of the assembly located at runtime to ensure that the same private key was used to create both the assembly seen when the reference was created (compile time) and when it is resolved (runtime).

6.2.1.4 Version Numbers

<asmDecl> ::= .ver <int32> : <int32> : <int32> : <int32> | ...

The version number of the assembly is specified as four 32-bit integers. This version number shall be captured at compile time and used as part of all references to the assembly within the compiled module. This standard places no other requirements on the use of the version numbers.

All standardized assemblies shall have the last two 32-bit integers set to 0. This standard places no other requirement on the use of the version numbers, although individual implementers are urged to avoid setting both of the last two 32-bit integers to 0 to avoid a possible collision with future standards.

Future versions of this standard shall change one or both of the first two 32-bit integers specified for a standardized assembly if any additional functionality is added or any additional features of the virtual machine are required to implement it. Furthermore, this standard shall change one or both of the first two 32-bit integers specified for the mscorlib assembly so that its version number may be used (if desired) to distinguish between different versions of the Virtual Execution system required to run programs conforming to that version of the standard.

NOTE

A conforming implementation may ignore version numbers entirely, or it may require that they match precisely when binding a reference, or any other behavior deemed appropriate. By convention:

The first of these is considered the major version number, and assemblies with the same name but different major versions are not interchangeable. This would be appropriate, for example, for a major rewrite of a product where backward compatibility cannot be assumed.

The second of these is considered the minor version number, and assemblies with the same name and major version but different minor versions indicate significant enhancements but with intention to be backward compatible. This would be appropriate, for example, on a "point release" of a product or a fully backward compatible new version of a product.

The third of these is considered the revision number, and assemblies with the same name, major and minor version number, but different revisions are intended to be fully interchangeable. This would be appropriate, for example, to fix a security hole in a previously released assembly.

The fourth of these is considered the build number, and assemblies that differ only by build number are intended to represent a recompilation from the same source. This would be appropriate, for example, because of processor, platform, or compiler changes.


6.2.2 Manifest Resources

A manifest resource is simply a named item of data associated with an assembly. A manifest resource is introduced using the .mresource directive, which adds the manifest resource to the assembly manifest begun by a preceding .assembly declaration.

ANNOTATION

Manifest resources are named items of data in a file that is part of the manifest. Both the file and how to access the data of interest in the file are specified in the manifest. This is distinct from specifying a file to be used as a whole, as described in the section following this one. A file used as a whole is often documentation, as opposed to the data within a file that is a manifest resource.


<decl> ::=

Section in Partition II

 
 .mresource [public | private] <dottedname>              { <manResDecl>* } 

5.10

| ...

 

If the manifest resource is declared public, it is exported from the assembly. If it is declared private, it is not exported and hence only available from within the assembly. The <dottedname> is the name of the resource, and the optional quoted string is a description of the resource.

<manResDecl> ::=

Description

Section in Partition II

 

.assembly extern <dottedname>

Manifest resource is in external assembly with name <dottedname>.

6.3

| .custom <customDecl>

Custom attribute.

20

| .file <dottedname> at <int32>

Manifest resource is in file <dottedname> at byte offset <int32>.

 

For a resource stored in a file that is not a module (for example, an attached text file), the file shall be declared in the manifest using a separate (top-level) .file declaration (see Partition II, section 6.2.3) and the byte offset shall be zero. Similarly, a resource that is defined in another assembly is referenced using .assembly extern, which requires that the assembly has been defined in a separate (top-level) .assembly extern directive (see Partition II, section 6.3).

6.2.3 Files in the Assembly

Assemblies may be associated with other files e.g., documentation and other files that are used during execution. The declaration .file is used to add a reference to such a file to the manifest of the assembly (see Partition II, section 21.19).

<decl> ::=

Section in Partition II

 

.file [nometadata] <filename> .hash = ( <bytes> ) [.entrypoint]

5.10

| ...

 

The attribute nometadata is specified if the file is not a module according to this specification. Files that are marked as nometadata may have any format; they are considered pure data files.

The <bytes> after the .hash specify a hash value computed for the file. The VES shall recompute this hash value prior to accessing this file and shall generate an exception if it does not match. The algorithm used to calculate this hash value is specified with .hash algorithm (see Partition II, section 6.2.1.1).

If specified, the .entrypoint directive indicates that the entry point of a multi-module assembly is contained in this file.

ANNOTATION

Implementation-Specific (Microsoft): If the hash value is not specified, it will be automatically computed by the assembly linker al when an assembly file is created using al. Even though the hash value is optional in the grammar for ilasm, it is required at runtime.


6.3 Referencing Assemblies

 <asmRefDecl> ::= .assembly extern <dottedname> [ graphics/ccc.gif as <dottedname> ]                  { <asmRefDecl>* } 

An assembly mediates all accesses from the files that it contains to other assemblies. This is done through the metadata by requiring that the manifest for the executing assembly contain a declaration for any assembly referenced by the executing code. The syntax .assembly extern as a top-level declaration is used for this purpose. The optional as clause provides an alias which allows ilasm to address external assemblies that have the same name, but that differ in version, culture, etc.

The dotted name used in .assembly extern shall exactly match the name of the assembly as declared with the .assembly directive in a case-sensitive manner. (So, even though an assembly might be stored within a file, within a file system that is case-blind, the names stored internally within metadata are case-sensitive, and shall match exactly.)

ANNOTATION

A complete program often consists of more than one assembly. In that case, the other assembly or assemblies that a given assembly might use are specified in the manifest. In ilasm, it is done with the .assembly extern directive.

Implementation-Specific (Microsoft): The assembly mscorlib contains many of the types and methods in the Base Class Library. For convenience, ilasm automatically inserts a .assembly extern mscorlib declaration if required.


<asmRefDecl> ::=

Description

Section in Partition II

 

.hash = ( <bytes> )

Hash of referenced assembly

6.2.3

| .custom <customDecl>

Custom attributes

20

| .culture <QSTRING>

Culture of the referenced assembly

6.2.1.2

| .publickeytoken = ( <bytes> )

The low 8 bytes of the SHA1 hash of the originator's public key

6.3

| .publickey = ( <bytes> )

The originator's full public key

6.2.1.3

| .ver <int32> : <int32> : <int32> : <int32>

Major version, minor version, revision, and build

6.2.1.4

These declarations are the same as those for .assembly declarations (Partition II, section 6.2.1), except for the addition of .publickeytoken. This declaration is used to store the low 8 bytes of the SHA1 hash of the originator's public key in the assembly reference, rather than the full public key.

An assembly reference can store either a full public key or an 8-byte "publickeytoken." Either can be used to validate that the same private key used to sign the assembly at compile time signed the assembly used at runtime. Neither is required to be present, and while both can be stored, this is not useful.

A conforming implementation of the CLI need not perform this validation, but it is permitted to do so, and it may refuse to load an assembly for which the validation fails. A conforming implementation of the CLI may also refuse to permit access to an assembly unless the assembly reference contains either the public key or the public key token. A conforming implementation of the CLI shall make the same access decision independent of whether a public key or a token is used.

RATIONALE

The full public key is cryptographically safer, but requires more storage space in the assembly reference.


 
 Example (informative): .assembly extern MyComponents { .publickey = (BB AA BB EE 11 22 33 00)   .hash = (2A 71 E9 47 F5 15 E6 07 35 E4 CB E3 B4 A1 D3 7F 7F A0 9C 24)   .ver 2:10:2002:0 } 

6.4 Declaring Modules

All CIL files are modules and are referenced by a logical name carried in the metadata rather than their file name. See Partition II, section 21.27.

<decl> ::=

Section in Partition II

| .module <filename>

5.10

| ...

 

 
 Example (informative): .module CountDown.exe 

ANNOTATION

Implementation-Specific (Microsoft): If the .module directive is missing, ilasm will automatically add a .module directive and set the module name to be the file name, including its extension in capital letters. For example, if the file is called "foo" and compiled into an executable, the module name will become "Foo.EXE."

Note that ilasm also generates a required GUID to uniquely identify this instance of the module and emits that into the Mvid metadata field: see Partition II, section 21.27.


6.5 Referencing Modules

When an item is in the current assembly but part of a different module than the one containing the manifest, the defining module shall be declared in the manifest of the assembly using the .module extern directive. The name used in the .module extern directive of the referencing assembly shall exactly match the name used in the .module directive (see Partition II, section 6.4) of the defining module. See Partition II, section 21.28.

<decl> ::=

Section in Partition II

| .module extern <filename>

5.10

| ...

 

 
 Example (informative): .module extern Counter.dll 

6.6 Declarations inside a Module or Assembly

Declarations inside a module or assembly are specified by the following grammar. More information on each option can be found in the corresponding section.

<decl> ::=

Section in Partition II

| .class <classHead> { <classMember>* }

9

| .custom <customDecl>

20

| .data <datadecl>

15.3.1

| .field <fieldDecl>

15

| .method <methodHead> { <methodBodyItem>* }

14

| <externSourceDecl>

5.7

| <securityDecl>

19

| ...

 

6.7 Exported Type Definitions

The manifest module, of which there can only be one per assembly, includes the .assembly statement. To export a type defined in any other module of an assembly requires an entry in the assembly's manifest. The following grammar is used to construct such an entry in the manifest:

<decl> ::=

Section in Partition II

 

.class extern <exportAttr> <dottedname> { <externClassDecl>* }

[21.14]

<externClassDecl> ::=

Section in Partition II

   .file <dottedname> | .class extern <dottedname> | .custom <customDecl> 

20

The <exportAttr> value shall be either public or nested public and shall match the visibility of the type.

For example, suppose an assembly consists of two modules: A.EXE and B.DLL. A.EXE contains the manifest. A public class "Foo" is defined in B.DLL. In order to export it that is, to make it visible by, and usable from, other assemblies a .class extern statement shall be included in A.EXE.

Conversely, a public class "Bar" defined in A.EXE does not need any .class extern statement.

RATIONALE

Tools should be able to retrieve a single module, the manifest module, to determine the complete set of types defined by the assembly. Therefore, information from other modules within the assembly is replicated in the manifest module. By convention, the manifest module is also known as the assembly.




The Common Language Infrastructure Annotated Standard (Microsoft. NET Development Series)
The Common Language Infrastructure Annotated Standard (Microsoft. NET Development Series)
ISBN: N/A
EAN: N/A
Year: 2002
Pages: 121

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net