Custom Attribute Declaration

Custom Attribute Declaration

The ILAsm syntax for declaring a custom attribute is as follows:

.custom <attribute_type> [ = ( <hexbytes> ) ]

or, considering the limitation imposed on <attribute_type> in the first release of the common language runtime:

.custom instance void <class_ref>::.ctor(<arg_list>)    [ = ( <hexbytes> ) ]

where <class_ref> is a fully qualified class reference, <arg_list> is an argument list of the instance constructor, and <hexbytes> is the sequence of two-digit hexadecimal numbers representing the bytes in the custom attribute’s blob.

You might have noticed a regrettable omission in the first release of ILAsm: the language does not allow you to specify the custom attribute value in “civilized” terms, requiring an explicit specification of the blob contents. For example, instead of writing

.custom instance void MyAttribute::.ctor(bool) = (true)

you must write

.custom instance void MyAttribute::.ctor(bool) = (01 00 01 00 00)

I expect this omission to be remedied in later releases of ILAsm and its compiler.

The owner of the custom attribute, or the metadata item to which the attribute is attached, is defined by the positioning of the custom attribute declaration. At first glance, the rule regarding the declaration of metadata items is simple: If the item declaration has a scope (for example, an assembly, a class, or a method), the custom attributes declared within this scope belong to the item. Otherwise—that is, if the item declaration has no scope (such items as a file, a module, or a field)—the custom attributes declared immediately after the item declaration belong to the item. For example, take a look at these excerpts from the disassembly of Mscorlib.dll:

.assembly mscorlib {    .custom instance void System.CLSCompliantAttribute::.ctor(bool)        = ( 01 00 01 00 00 )     .custom instance void          System.Resources.NeutralResourcesLanguageAttribute::.ctor(string)       = ( 01 00 05 65 6E 2D 55 53 00 00 )   // ...en-US..     }  .module CommonLanguageRuntimeLibrary .custom instance void     System.Security.UnverifiableCodeAttribute::.ctor()     = ( 01 00 00 00 )  .class interface public abstract auto ansi IEnumerable {    .custom instance void       System.Runtime.InteropServices.GuidAttribute::.ctor(string)        = ( 01 00 24 34 39 36 42 30 41 42 45 2D 43 44 45 45           2D 31 31 64 33 2D 38 38 45 38 2D 30 30 39 30 32           37 35 34 43 34 33 41 00 00 )    .method public hidebysig newslot virtual abstract        instance class System.Collections.IEnumerator        GetEnumerator() cil managed    {       .custom instance void          System.Runtime.InteropServices.DispIdAttribute::.ctor(int32)          = ( 01 00 FC FF FF FF 00 00 )            } // End of method IEnumerable::GetEnumerator     } // End of class IEnumerable 

This is in stark contrast to the way custom attributes are declared, for instance, in Microsoft Visual C# .NET, where a custom attribute belonging to an item immediately precedes the item declaration. For example, the following is an excerpt showing the Visual C# .NET declaration of the interface IEnumerable mentioned in the preceding code:

    [Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")]     public interface IEnumerable     {        [DispId(-4)]        IEnumerator GetEnumerator();     }

The ILAsm rule specifying that custom attribute ownership is defined by the position of the attribute declaration can play tricks on you if you don’t pay attention, however. Don’t forget that when a nonscoped item is declared within the scope of another item, the custom attribute’s ownership immediately switches to this newly declared item. Because of that, the custom attributes belonging to a scoped item cannot be declared just anywhere within the item’s scope. The following code snippet illustrates the point:

.class public MyClass  {    .custom instance void MyClassAttribute::.ctor()=(01 00 00 00)    .field int32 MyField    .custom instance void MyFieldAttribute::.ctor()=(01 00 00 00)    .method public int32 MyMethod([opt]int32 J)    {       .custom instance void MyMethodAttribute::.ctor()=(01 00 00 00)       .param[1] = int32(123456)       .custom instance void MyParamAttribute::.ctor()=(01 00 00 00)           } }

To avoid possible confusion about the ownership of a custom attribute, it’s better to declare an item’s custom attributes as soon as the item scope is opened.

The preceding discussion covers the rules for assigning custom attributes to items that are declared explicitly. Obviously, these rules cannot be applied to metadata items, which are declared implicitly, simply by their appearance in ILAsm directives and instructions. After all, such metadata items as TypeRefs, TypeSpecs, and MemberRefs might want their fair share of custom attributes, too.

To resolve this problem, ILAsm offers another form of the custom attribute declaration, with explicit specification of the custom attribute owner:

.custom <owner_spec> instance void <class_ref>::.ctor(<arg_list>)          [ = ( <hexbytes> ) ]

where

<owner_spec> ::= <class_ref>   <type_spec>                     method <method_ref>   field <field_ref>

For example:

.custom ([mscorlib]System.String)          instance void MyTypeRefAttribute::.ctor()=(01 00 00 00) .custom ([mscorlib]System.String[])          instance void MyTypeSpecAttribute::.ctor()=(01 00 00 00) .custom (method instance void Foo::Bar(int32,int32))          instance void MyMemberRefAttribute1::.ctor()=(01 00 00 00) .custom (field int32 Foo::Baz)          instance void MyMemberRefAttribute2::.ctor()=(01 00 00 00)

Custom attribute declarations in their full form can appear anywhere within the ILAsm source code, because the owner of a custom attribute is specified explicitly and doesn’t have to be inferred from the positioning of the custom attribute declaration. The IL Disassembler (ILDASM) puts the custom attribute declarations in full form at the end of the source code dump, before the data dump.

Two additional categories of metadata items can in principle own custom attributes: InterfaceImpls and StandAloneSigs. The first release of ILAsm offers no language means to define custom attributes belonging to these items, another omission to be corrected in future revisions of ILAsm and its compiler. Of course, so far no compiler or other tool has generated custom attributes for these items, but you never know. The tools develop quickly, and the custom attributes proliferate even more quickly, so sooner or later somebody will manage to assign a custom attribute to an interface implementation or a stand-alone signature.

On the other hand, many custom attributes are intended for the compilers’ internal consumption and never make it past the complete compilation process. ILAsm needs to be concerned only with those custom attributes that are recognized by the common language runtime or the tools operating with managed PE files, such as the assembly linker (AL) or the debuggers.



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

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