Explicit Layouts and Union Declaration

Explicit Layouts and Union Declaration

Although instance fields cannot be mapped to data, it is possible to manipulate the positioning of these fields directly. As you might remember from Chapter 6, a class or a value type can have an explicit flag, a special flag indicating that the metadata contains exact instructions for the loader regarding the layout of this class. This information is kept in the FieldLayout metadata table, whose records contain these two entries:

  • OffSet (4-byte unsigned integer)  The relative offset of the field in the class layout (not an RVA).

  • Field (RID to the Field table)  The index of the field for which the offset is specified.

In ILAsm, the field offset is specified by putting the offset value in square brackets immediately after the .field keyword, as shown here:

.class public value sealed explicit MyStruct {    .field [0] public int32 ii    .field [4] public float64 dd    .field [12] public bool bb }

Only instance fields can have offsets specified. Because static fields are not part of the class instance layout, specifying explicit offsets for them is meaningless and is considered a metadata error. If an offset is specified for a static field, the loader behaves the same way it does with mapped instance fields: if the field is static, the loader does not check to see whether the field has an offset specified. Consequently, FieldLayout records referencing the static fields are nothing more than a waste of memory.

In a class that has an explicit layout, all the instance fields must have specified offsets. If one of the instance fields does not have an associated FieldLayout record, the loader throws a TypeLoad exception and aborts the loading. Obviously, a field can have only one offset, so duplicate FieldLayout records that have the same Field entry are illegal. This is not checked at run time because this metadata invalidity is not critical: the loader takes the first available FieldLayout record for the current field and ignores any duplicates.

The placement of object references (classes, arrays) is subject to a general limitation: the fields of object reference types must be aligned on pointer size—either 4 or 8 bytes, depending on the platform:

.class public value sealed explicit MyStruct {    .field [0] public int16 ii    .field [2] public string str //Illegal on 32-bit and 64-bit    .field [6] public int16 jj    .field [8] public int32 kk    .field [12] public object oo //Illegal on 64-bit platform    .field [16] public int32[] iArr //Legal on both platforms }

Explicit layout is a standard way to implement unions in IL. By explicitly specifying field offsets, we can make fields overlap however we want. Let’s suppose, for example, that we want to treat a 4-byte unsigned integer as such, or as a pair of 2-byte words, or as 4 bytes. In C/C++ notation, the respective constructs look like this:

union MultiDword {    DWORD dw;    union {       struct {          WORD w1;          WORD w2;       };       struct {          BYTE b1;          BYTE b2;          BYTE b3;          BYTE b4;       };    }; };

In ILAsm, the same union will be written like so:

.class public value sealed explicit MultiDword       {    .field [0] public unsigned int32 dw    .field [0] public unsigned int16 w1    .field [2] public unsigned int16 w2    .field [0] public unsigned int8 b1    .field [1] public unsigned int8 b2    .field [2] public unsigned int8 b3    .field [3] public unsigned int8 b4 }

The only limitation imposed on the explicit-layout unions is that if the overlapping fields contain object references, these object references must not overlap with any other field:

.class public value sealed explicit StrAndIndex {    .field [0] public string Str // Reference, size 4 bytes                                  // on 32-bit platform    .field [4] public unsigned int32 Index  } .class public value sealed explicit MyUnion {    .field [0] public valuetype StrAndIndex str_and_index    .field [0] public unsigned int64 whole_thing // Illegal!    .field [0] public string str // Illegal!    .field [2] public unsigned int32 half_and_half // Illegal!    .field [4] public unsigned int32 index // Legal, object reference                                           // not overlapped }

Such “unionizing” of the object references would provide the means for directly modifying these references, which could thoroughly disrupt the functioning of the garbage collector. The loader checks explicit layouts for object reference overlap; if any is found, it throws a TypeLoad exception and aborts the loading.

A field can also have an associated FieldLayout record if the owner of the field has a sequential layout. In this case, the OffSet entry of the FieldLayout record holds a field ordinal rather than an offset. The fields belonging to a sequential-layout class needn’t have associated FieldLayout records, but if one of the class’s fields has such an associated record, all the rest must have one too.



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