Search code examples
.netcilildasm

Different types have same signatures in CIL


I have one field defined in CIL like this:

.field public int32 modopt(void*) fld

I compile this to an assembly. Now I change it to:

.field public int32 modopt(int16) fld

Both how is it possible now, that ILDASM reports (when shown as hex) both those fields as this?

Field #1 (04000001)
-------------------------------------------------------
    Field Name: fld (04000001)
    Flags     : [Public]  (00000006)
    CallCnvntn: [FIELD]
    Field type:  CMOD_OPT 1b000001 I4
    Signature : 06 20 06 08 

This code looks for both fields exactly the same (actually I've created the second field to match the reported signature). The signature obviously matches the second field, but the signature of the first field should look like this: 06 20 0f 01 08! What am I missing here?

Edit:

C# cannot emit this type of field, throwing an exception about pointer and array types not supported for custom type modifiers, so this apparently solves the signature mismatch. But the question why ILDASM allows creating an invalid signature which it cannot decompile remains.

Edit #2:

It seems ILASM is actually creating correct IL, there is a difference in the hex dump I missed last time:

//the first assembly
TypeSpec #1 (1b000001)
-------------------------------------------------------
    TypeSpec : Ptr Void
    Signature: 0f 01 

//the second assembly
TypeSpec #1 (1b000001)
-------------------------------------------------------
    TypeSpec : I2
    Signature: 06 

So there is just a bug in ILDASM hex dump reporting wrong member signature (though I wonder where the 06 in the wrong signature came from).


Solution

  • Let's try to build the field signature manually based on the specification. To start, field signature is defined in §II.23.2.4. For our case with one custom modifier, it will be:

    FIELD CustomMod Type
    

    Since FIELD is defined as 0x06, we have:

    06 CustomMod Type
    

    Our custom modifier is modopt, so we get (based on §II.23.2.7):

    06 CMOD_OPT TypeDefOrRefOrSpecEncoded Type
    

    CMOD_OPT is 0x20 (§II.23.1.16):

    06 20 TypeDefOrRefOrSpecEncoded Type
    

    We want to reference TypeSpec 0x1b000001, which is encoded as 0b110 (10 for TypeSpec, 1 for 0x000001, §II.23.2.8). This is then "compressed" into the single byte 0x06 (§II.23.2):

    06 20 06 Type
    

    Finally, the type is int32, which is ELEMENT_TYPE_I4 = 0x08 (§II.23.2.12 and §II.23.1.16):

    06 20 06 08
    

    So we get exactly the same signature as the one shown in ILDasm.