Method Metadata

Method Metadata

Similar to field-related metadata, method-related metadata involves definition-specific and reference-specific metadata. In addition, method-related metadata includes method implementation, discussed later in this chapter, as well as method semantics, method interoperability, and security metadata. (Chapter 12, “Events and Properties,” describes method semantics; Chapter 15, “Managed and Unmanaged Code Interoperation,” examines method interoperability; and Chapter 14, “Security Attributes,” includes method security.) The diagram in Figure 9-1 shows the metadata tables involved in method definition and referencing implementation and their mutual dependencies. To avoid cluttering the illustration, I have not included metadata tables involved in the other three method-related aspects: method semantics, method interoperability, and security metadata.

Figure 9-1 Metadata tables related to method definition and referencing.

Method Table Record Entries

The central table for method definition is the Method table, which has the associated token type mdtMethodDef (0x06000000). A record in the Method table has six entries:

  • RVA (4-byte unsigned integer)  The relative virtual address (RVA) of the method body in the module. The method body consists of header, IL code, and structured exception handling descriptors. The RVA must point to a read-only section of the PE file.

  • ImplFlags (2-byte unsigned integer)  Implementation binary flags indicating the specifics of the method implementation.

  • Flags (2-byte unsigned integer)  Binary flags indicating the method’s accessibility and other characteristics.

  • Name (offset in the #Strings stream)  The name of the method. This entry must index a string of positive length no longer than 1023 bytes in UTF-8 encoding.

  • Signature (offset in the #Blob stream)  The method signature. This entry must index a blob of positive size and must comply with the method definition signature rules described in Chapter 7, “Primitive Types and Signatures.”

  • ParamList (RID to the Param table)  The record index of the start of the parameter list belonging to this method. The end of the parameter list is defined by the start of the next method’s parameter list or by the end of the Param table.

As in the case of field definition, Method records carry no information regarding the parent class of the method. Instead, the Method table is referenced in the MethodList entries of TypeDef records, indexing the start of Method records belonging to each particular TypeDef.

The RVA entry must be 0 or must hold a valid relative virtual address pointing to a read-only section of the image file. If the RVA value points to a read/write section, the loader will reject the method unless the application is run from a local drive with all security checks disabled. If the RVA entry holds 0, it means that this method is implemented somewhere else (imported from a COM library, platform-invoked from an unmanaged DLL, or simply implemented by descendants of the class owning this method). All these cases are described by special combinations of method flags and implementation flags.

The IL assembly language (ILAsm) syntax for method definition is the following:

<method_def> ::=  .method <flags> <call_conv> <ret_type> <name>(<arg_list><impl> {     <method_body> }

where <call_conv>, <ret_type>, and <arg_list> are the method calling convention, the return type, and the argument list defining the method signature.

Method Flags

The nonterminal symbol <flags> identifies the method binary flags, which are defined in the enumeration CorMethodAttr in CorHdr.h and are described in the following list.

  • Accessibility flags (mask 0x0007), which are similar to the accessibility flags of fields:

    • privatescope (0x0000)  This is the default accessibility. A private scope method is exempt from the requirement of having a unique triad of owner, name, and signature and hence must always be referenced by a MethodDef token and never by a MemberRef token. Otherwise, this accessibility is the same as that specified by the private flag.

    • private (0x0001)  The method is accessible from its owner and from classes nested in the method’s owner.

    • famandassem (0x0002)  The method is accessible from types belonging to the owner’s family—that is, the owner itself and all its descendants—defined in the current assembly.

    • assembly (0x0003)  The method is accessible from types defined in the current assembly.

    • family (0x0004)  The method is accessible from the owner’s family.

    • famorassem (0x0005)  The method is accessible from the owner’s family and from all types defined in the current assembly.

    • public (0x0006)  The method is accessible from any type.

  • Contract flags (mask 0x00F0):

    • static (0x0010)  The method is static, shared by all instances of the type.

    • final (0x0020)  The method cannot be overridden. This flag must be paired with the virtual flag.

    • virtual (0x0040)  The method is virtual. This flag cannot be paired with the static flag.

    • hidebysig (0x0080)  The method hides all methods of the parent classes that have a matching signature and name (as opposed to having a matching name only). This flag is ignored by the common language runtime and is provided for the use of compilers only. The ILAsm compiler recognizes this flag but does not use it for its own purposes.

  • Virtual method table (v-table) control flag (mask 0x0100):

    • newslot (0x0100)  A new slot is created in the class’s v-table for this virtual method so that it does not override the virtual method of the same name and signature this class inherited from its base class. This flag can be used only in conjunction with the virtual flag.

  • Implementation flags (mask 0x2C08):

    • abstract (0x0400)  The method is abstract; no implementation is provided. This method must be overridden by the non-abstract descendants of the class owning the abstract method. Any class owning an abstract method must have its own abstract flag set. The RVA entry of an abstract method record must be 0.

    • specialname (0x0800)  The method is special in some way, as described by the name.

    • pinvokeimpl( <pinvoke_spec> ) (0x2000)  The method has unmanaged implementation and is called through the platform invocation mechanism P/Invoke, discussed in Chapter 15. <pinvoke_spec> in parentheses defines the implementation map, which is a record in the ImplMap metadata table specifying the unmanaged DLL exporting the method and the method’s unmanaged calling convention. If <pinvoke_spec> is provided, the method’s RVA must be 0, since the method is implemented externally. If <pinvoke_spec> is not provided—that is, the parentheses are empty—the defined method is a local P/Invoke, implemented in unmanaged native code embedded in the current PE file; in this case, its RVA must not be 0.

    • unmanagedexp (0x0008)  The managed method is exposed as an unmanaged export. This flag is not currently used by the common language runtime.

  • Reserved flags (cannot be set explicitly; mask 0xD000):

    • rtspecialname (0x1000)  The method has a special name reserved for the internal use of the runtime. Four method names are reserved: .ctor for instance constructors, .cctor for class constructors, _VtblGap* for v-table placeholders, and _Deleted* for methods marked for deletion but not actually removed from metadata. The keyword rtspecialname is ignored by the ILAsm compiler and is displayed by the IL Disassembler for informational purposes only. This flag must be accompanied by a specialname flag.

    • [no ILAsm keyword] (0x4000)  The method either has an associated DeclSecurity metadata record that holds security details concerning access to the method or has the associated custom attribute System.Security.SuppressUnmanagedCodeSecurityAttribute.

    • reqsecobj (0x8000)  Because this method calls another method containing security code, it requires an additional stack slot for a security object. This flag is formally under the Reserved mask, so it cannot be set explicitly. Setting this flag requires emitting the pseudocustom attribute System.Security.DynamicSecurityMethod- Attribute. When the ILAsm compiler encounters the keyword reqsecobj, it does exactly that: emits the pseudo-custom attribute and thus sets this “reserved” flag.

    note

    I’ve used the word implementation here and there rather extensively; perhaps some clarification is in order, to avoid confusion. First, note that method implementation in the sense of one method providing implementation for another is discussed later in this chapter. Implementation-specific flags of a method are not related to that topic; rather, they indicate the features of implementation of the current method. Second, a Method record contains two binary flag entries: Flags and ImplFlags (implementation flags). It so happens that part of Flags (mask 0x2C08) is also implementation-related. Thus far, I have been talking about this part of Flags. For information about ImplFlags, see “Method Implementation Flags” later in this chapter.

Method Name

A method name in ILAsm is either a simple name or one of the two keywords .ctor or .cctor. As you already know, .ctor is the reserved name for instance constructors, while .cctor is reserved for class constructors, or type initializers. In ILAsm, .ctor and .cctor are keywords, so they should not be single-quoted as any other irregular simple name.

The general requirements for a method name are straightforward: the name must contain 1 to 1023 bytes in UTF-8 encoding, and it should not match one of the four reserved method names—unless you really mean it. If you give a method one of these reserved names, the common language runtime treats the method according to this name.

Method Implementation Flags

The nonterminal symbol <impl> in the method definition form denotes the implementation flags of the method (the ImplFlags entry of a Method record). The implementation flags are defined in the enumeration CorMethodImpl in CorHdr.h and are described in the following list.

  • Code type (mask 0x0003):

    • cil (0x0000)  The default. The method is implemented in common intermediate language (CIL, a.k.a. IL, MSIL).

    • native (0x0001)  The method is implemented in native platform-specific code.

    • optil (0x0002)  The method is implemented in optimized IL. Because the optimized IL is not supported in the first release of the common language runtime, this flag should not be set.

    • runtime (0x0003)  The method implementation is provided by the runtime itself. If this flag is set, the RVA of the method must be 0.

  • Code management (mask 0x0004):

    • managed (0x0000)  The default. The code is managed. In the first release of the runtime, this flag cannot be paired with the native flag.

    • unmanaged (0x0004)  The code is unmanaged. This flag must be paired with the native flag.

  • Implementation and interoperability (mask 0x10D8):

    • forwardref (0x0010)  The method is defined, but the IL code of the method is not supplied. This flag is used primarily in edit-and-continue scenarios and in managed object files, produced by the Microsoft Managed C++ (MC++) compiler. This flag should not be set for any of the methods in a managed PE file.

    • preservesig (0x0080)  The method signature must not be mangled during the interoperation with classic COM code, which is discussed in Chapter 15.

    • internalcall (0x1000)  Reserved for internal use. This flag indicates that the method is internal to the runtime and must be called in a special way. If this flag is set, the RVA of the method must be 0.

    • synchronized (0x0020)  The method must be executed in single-threaded mode only. Methods belonging to value types cannot have this flag set.

    • noinlining (0x0008)  The runtime is not allowed to inline the method—that is, to replace the method call with explicit insertion of the method’s IL code.

Take a look at the examples shown here:

.method public static int32 Diff(int32,int32cil managed{     } .method public void .ctor( ) runtime internalcall {}

Method Parameters

Method parameters reside in the Param metadata table, whose records have three entries:

  • Flags (2-byte unsigned integer)  Binary flags characterizing the parameter.

  • Sequence (2-byte unsigned integer)  The sequence number of the parameter, with 0 corresponding to the method return.

  • Name (offset in the #Strings stream)  The name of the parameter, which can be zero-length. For the method return, it must be zero-length.

Parameter flags are defined in the enumeration CorParamAttr in CorHdr.h and are described in the following list.

  • Input/output flags (mask 0x0013):

    • in (0x0001)  Input parameter.

    • out (0x0002)  Output parameter.

    • opt (0x0010)  Optional parameter.

  • Reserved flags (cannot be set explicitly; mask 0xF000):

    • [no ILAsm keyword] (0x1000)  The parameter has an associated Constant record. The flag is set by the metadata emission API when the respective Constant record is emitted.

    • marshal(<native_type>) (0x2000)  The parameter has an associated FieldMarshal record specifying how the parameter must be marshaled when consumed by unmanaged code. This is similar to the marshal( ) construct of a field.

To describe the ILAsm syntax of parameter definition, let me remind you of the method definition form:

<method_def> ::=  .method <flags> <call_conv> <ret_type> <name>(<arg_list><impl> {     <method_body> }

where

<ret_type> ::=  <type> [marshal(<native_type>)],  <arg_list> ::= [ <arg> [,<arg>*] ],  <arg> ::= [ [<in_out_flag>]* ] <type> [marshal(<native_type>)]            [<p_name>] <in_out_flag> ::= in   out   opt

Obviously, <p_name> is the name of the parameter, which, if provided, must be a simple name.

Notice the difference in positioning of the marshaling specification in a parameter and in a field definition: in a parameter definition, the marshaling specification follows the <type>; in a field definition, the marshaling specification precedes the <type>. Here is an example of parameter definitions:

.method public static int32 marshal(int) Diff( [inint32 marshal(int) First, [inint32 marshal(int) Second) {     }

The syntax just shown takes care of all the entries of a Param record (Flags, Sequence, Name) and, if needed, those of the associated FieldMarshal record (Parent, NativeType). To set the default values for the parameters, which are records in the Constant table, we need to add parameter specifications within the method scope:

<param_const_def> ::= .param [<sequence>] = <const_type> [ (<value>) ]

<sequence> is the parameter’s sequence number. This number should not be 0, because a 0 sequence number corresponds to the return type, and a “default return value” does not make sense. <const_type> and <value> are the same as for field default value definitions, described in Chapter 8, “Fields and Data Constants.” For example:

.method public static int32 marshal(int) Diff( [inint32 marshal(int) First, [optint32 marshal(int) Second) {    .param [2] = int32(0)     }

According to the common language runtime metadata model, it is not necessary to emit a Param record for each return or argument of a method. Rather, it must be done only if we want to specify the name, flags, marshaling, or default value. The ILAsm compiler emits Param records for all arguments unconditionally and for a method return only if marshaling is specified. Name, flags, and default value are not applicable to a method return.

Referencing the Methods

Method references, like field references, translate into either MethodDef tokens or MemeberRef tokens. As a rule, a reference to a locally defined method translates into a MethodDef token. However, even a locally defined method can be represented by a MemberRef token; and in certain cases, such as references to vararg methods, it must be represented by a MemberRef token.

The ILAsm syntax for method referencing is as follows:

<method_ref> ::=  [method<call_conv> <ret_type> <class_ref>::<name>(<arg_list>)

The method keyword, with no leading dot, is used in the following two cases in which the kind of metadata item being referenced is not clear from the context:

  • When a method is referenced as an argument of the ldtoken instruction.

  • When a method is referenced in an explicit specification of a custom attribute’s owner. (See Chapter 13, “Custom Attributes,” for more information.)

The same rules apply to the use of the field keyword in field references. The method keyword is used in one additional context: when specifying a function pointer as a type of field, variable, or parameter. That case, however, involves not a method reference but a signature definition.

Flags, implementation flags, and parameter-related information (names, marshaling, and so on) are not specified in a method reference. As you know, a MemberRef record holds only the member’s parent token, name, and signature—the three elements needed to identify a method or a field unambiguously. Here are a few examples of method references:

call instance void Foo::Bar(int32,int32) ldtoken method instance void Foo::Bar(int32,int32)

In the case of method references, the nonterminal symbol <class_ref> can be a TypeDef, TypeRef, TypeSpec, or ModuleRef:

call instance void Foo::Bar(int32,int32) call instance void [OtherAssembly]Foo::Bar(int32,int32) call instance void Foo[]::Bar(int32,int32) call void [.module Other.dll]::Bar(int32,int32)

Method Implementation Metadata

Method implementations represent specific metadata describing method overriding, in which one method’s implementation is substituted for another method’s implementation. The method implementation metadata is held in the MethodImpl table, which has the following structure:

  • Class (RID to the TypeDef table)  The record index of the TypeDef implementing a method—in other words, replacing the method’s implementation with that of another method.

  • MethodBody (coded token of type MethodDefOrRef)  A token indexing a record in the Method table that corresponds to the implementing method—that is, to the method whose implementation substitutes for another method’s implementation. A coded token of this type can point to the MemberRef table as well, but this is illegal in the first release of the common language runtime. The method indexed by MethodBody must be virtual. In the first release of the runtime, the method indexed by MethodBody must belong to the class indexed by the Class entry.

  • MethodDecl (coded token of type MethodDefOrRef)  A token indexing a record in the Method table or the MemberRef table that corresponds to the implemented method—that is, to the method whose implementation is being replaced by another method’s implementation. The method indexed by MethodDecl must be virtual.



Inside Microsoft. NET IL Assembler
Inside Microsoft .NET IL Assembler
ISBN: 0735615470
EAN: 2147483647
Year: 2005
Pages: 147
Authors: SERGE LIDIN

Similar book on Amazon

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