Mapped Fields

Mapped Fields

It is possible to provide unconditional initialization for static fields by mapping the fields to data defined in the PE file and setting this data to the initializing values. The syntax for mapping a field to data in ILAsm is the following:

<mapped_field_decl> ::= .field <flags> <type> <name> at <data_label>

Here’s an example:

.field public static int64 ii at data_ii

The nonterminal symbol <data_label> is a simple name labeling the data segment to which the field is mapped. The ILAsm compiler allows a field to be mapped either to the “normal” data section (.sdata) or to the thread local storage (.tls), depending on the data declaration to which the field mapping refers. A field can be mapped only to data residing in the same module as the field declaration. (For information about data declaration, see the following section, “Data Constants Declaration.”)

Mapping a field results in emitting a record of the FieldRVA table, which contains two entries:

  • RVA (4-byte unsigned integer)  The relative virtual address of the data to which the field is mapped.

  • Field (RID to the Field table)  The index of the Field record being mapped.

Two or more fields can be mapped to the same location, but each field can be mapped to one location only. Duplicate FieldRVA records with the same Field values and different RVA values are therefore considered invalid metadata. The loader is not particular about duplicate FieldRVA records, however; it simply uses the first one available for the field and ignores the rest.

The field mapping technique has some catches. The first catch (well, not much of a catch, actually) is that, obviously, only static fields can be mapped. Even if we could map instance fields, each instance would be mapped to the same physical memory, making the fields de facto static—shared by all instances—anyway. Mapping instance fields is considered invalid metadata, but it has no serious consequences for the loader—if a field is not static, the loader does not even check to see whether the field is mapped. The only real effect of mapping instance fields is a bloated FieldRVA table. The ILAsm compiler treats mapping of an instance field as an error and produces an error message.

The second catch is that a field cannot be mapped if its type contains object references (objects or arrays). Because the data sections are out of the garbage collector’s reach, the validity of object references placed in the data sections cannot be guaranteed. If the loader finds object references in a mapped field type, it throws a TypeLoad exception and aborts the loading, even if the code is run in full trust mode from a local drive and all security-related checks are disabled. The loader checks for the presence of object references on all levels of the field type—in other words, it checks the types of all the fields that make up the type, and checks the types of fields that make up those types, and so on.

The third catch is that a field cannot be mapped if its type contains nonpublic instance fields. The reasoning behind this limitation is that if we map a field with a type containing nonpublic members, we can map another field of some all-public type to the same location and, through this second mapping, get unlimited access to nonpublic member fields of the first type. The loader checks for the presence of nonpublic members on all levels of the mapped field type and throws a TypeLoad exception if it finds such members. This check, unlike the check for object references, is performed only when code verification is required; it is disabled when the code is run from the local drive in full trust mode.

Note, however, that a mapped field itself can be declared nonpublic without ill consequences. This is based on the simple assumption that if developers decide to overlap their own nonpublic field and thus defy the accessibility control mechanism of the common language runtime object model, they probably know what they are doing.

The last catch worth mentioning is that the initialization data is provided “as is,” exactly as it is defined in the PE file. And if you run the code on a platform other than the one on which the PE file was created, you can face some unpleasant consequences. As a trivial example, suppose that you map an int32 field to data containing bytes 0xAA, 0xBB, 0xCC, and 0xDD. On a little endian platform (for instance, an Intel platform), the field is initialized to 0xDDCCBBAA, while on a big endian platform well, you get the picture.

All these catches do not preclude the compilers from using field mapping for initialization.



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