开发者

Rogue entries in TypeSpec metadata table

I have a .NET library and I am trying to understand more about the inner workings of .NET. So I am going through ECMA-335 specification and utilizing the CFF Explorer VII.

My question is, in the TypeSpec table the Signature is an index in to the Blob heap and should be a TypeSpec signature as described in section 23.2.14. Which means it can be a PTR, FNPTR, ARRAY, SZARRAY, GENERICINSTANCE (ELEMENT_TYPE_ removed for brevity).

However I have two entries in this TypeSpec table that are seemingly not referenced by any other table in the metadata and are of type VAR 0x13 and MVAR 0x1e.

This assembly is compiled in VS2010 against .NET 4.

The ECMA-335 would lead me to believe this is an error but it has been compiled using the MS C# compiler.

Does anyone know what they are and what they mean开发者_运维技巧?

Update:

After lots of messing around this code creates those two entries in the TypeSpec table.

public class AllOutputTypesClass<T> {
    public void GenericMethod<N>(N anItem) {
        string s = anItem.ToString();
    }

    public string GenericMethod<N>(T anItem, N secondItem) {
        return anItem.ToString();
    }
}


Both TypeSpec tokens in your example are referenced from the IL in the method implementations, not from the metadata. For example, the IL for one of your methods looks like this:

.method public hidebysig instance string 
        GenericMethod<N>(!T anItem,
                         !!N secondItem) cil managed
{
  // Code size       19 (0x13)
  .maxstack  1
  .locals init (string V_0)
  IL_0000:  nop
  IL_0001:  ldarga.s   anItem
  IL_0003:  constrained. !T
  IL_0009:  callvirt   instance string [mscorlib]System.Object::ToString()
  IL_000e:  stloc.0
  IL_000f:  br.s       IL_0011
  IL_0011:  ldloc.0
  IL_0012:  ret
} // end of method AllOutputTypesClass`1::GenericMethod

The TypeSpec token is used to represent the "!T" in the constrained prefix. You'll see a similar reference to the other TypeSpec token in the body of the other method.


If you use ILDasm you can get a good breakdown of the methods, go to the View -> Meta Info -> select More Hex. Then go to the View -> Meta Info -> Show!

Here is the breakdown for the second method:

    Method #2 (06000002) 
-------------------------------------------------------
    MethodName: GenericMethod (06000002)
    Flags     : [Public] [HideBySig] [ReuseSlot]  (00000086)
    RVA       : 0x0000206c
    ImplFlags : [IL] [Managed]  (00000000)
    CallCnvntn: [DEFAULT]
    hasThis 
    generic 
    Type Arity:1 
    ReturnType: String
    2 Arguments
        Argument #1:  Var!0
        Argument #2:  MVar!!0
    Signature : 30 01 02 0e 13 00 1e 00 
    1 Generic Parameters
        (0) GenericParamToken : (2a000003) Name : N flags: 00000000 Owner: 06000002
    2 Parameters
        (1) ParamToken : (08000002) Name : anItem flags: [none] (00000000)
        (2) ParamToken : (08000003) Name : secondItem flags: [none] (00000000)

If you scroll down further you'll see the TypeSpec table entries too.

TypeSpec #1 (1b000001)

TypeSpec : MVar!!0
Signature: 1e 00 

TypeSpec #2 (1b000002)

TypeSpec : Var!0
Signature: 13 00 

What ILdasm shows above is the VAR (13 00) is the generic !T passed at the class level (generic param in type definition) and the MVAR (1e 00) is the generic !!N passed at the method level (generic param in method definition).

However ... you already know that much, Orion has your answer - the entries in the TypeSpec table are being used in the IL. One entry is used in one method and the other is the other method. You can see this in ILdasm when you look at the methods:

    .method /*06000001*/ public hidebysig instance void 
        'GenericMethod'<'N'>(!!'N' 'anItem') cil managed
// SIG: 30 01 01 01 1E 00
{
  // Method begins at RVA 0x2050
  // Code size       16 (0x10)
  .maxstack  1
  .locals /*11000001*/ init ([0] string 's')
  IL_0000:  /* 00   |                  */ nop
  IL_0001:  /* 0F   | 01               */ ldarga.s   'anItem'
  IL_0003:  /* FE16 | (1B)000001       */ constrained. !!'N'/*1B000001*/
  IL_0009:  /* 6F   | (0A)000011       */ callvirt   instance string ['mscorlib'/*23000001*/]'System'.'Object'/*01000001*/::'ToString'() /* 0A000011 */
  IL_000e:  /* 0A   |                  */ stloc.0
  IL_000f:  /* 2A   |                  */ ret
} // end of method 'AllOutputTypesClass`1'::'GenericMethod'

and

.method /*06000002*/ public hidebysig instance string 
        'GenericMethod'<'N'>(!'T' 'anItem',
                             !!'N' 'secondItem') cil managed
// SIG: 30 01 02 0E 13 00 1E 00
{
  // Method begins at RVA 0x206c
  // Code size       19 (0x13)
  .maxstack  1
  .locals /*11000001*/ init ([0] string 'CS$1$0000')
  IL_0000:  /* 00   |                  */ nop
  IL_0001:  /* 0F   | 01               */ ldarga.s   'anItem'
  IL_0003:  /* FE16 | (1B)000002       */ constrained. !'T'/*1B000002*/
  IL_0009:  /* 6F   | (0A)000011       */ callvirt   instance string ['mscorlib'/*23000001*/]'System'.'Object'/*01000001*/::'ToString'() /* 0A000011 */
  IL_000e:  /* 0A   |                  */ stloc.0
  IL_000f:  /* 2B   | 00               */ br.s       IL_0011
  IL_0011:  /* 06   |                  */ ldloc.0
  IL_0012:  /* 2A   |                  */ ret
} // end of method 'AllOutputTypesClass`1'::'GenericMethod'

The 0x1b table is the TypeSpec, so the following lines from the methods above show the usage of the 2 rows you were wondering about:

  IL_0003:  /* FE16 | (1B)000001       */ constrained. !!'N'/*1B000001*/

and

IL_0003:  /* FE16 | (1B)000002       */ constrained. !'T'/*1B000002*/
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜