Мошеннические записи в таблице метаданных TypeSpec - PullRequest
5 голосов
/ 26 августа 2011

У меня есть библиотека .NET, и я пытаюсь понять больше о внутренней работе .NET.Итак, я прохожу спецификацию ECMA-335 и использую CFF Explorer VII.

Мой вопрос заключается в том, что в таблице TypeSpec подпись является индексом в куче BLOB-объектов и должна быть подписью TypeSpec, как описано в разделе23.2.14.Это означает, что это может быть PTR, FNPTR, ARRAY, SZARRAY, GENERICINSTANCE (ELEMENT_TYPE_ удалено для краткости).

Однако у меня есть две записи в этой таблице TypeSpec, на которые, по-видимому, не ссылаются никакие другие таблицы в метаданных иимеют тип VAR 0x13 и MVAR 0x1e.

Эта сборка скомпилирована в VS2010 для .NET 4.

ECMA-335 заставит меня поверить, что это ошибка, но она была скомпилированаиспользуя компилятор MS C #.

Кто-нибудь знает, что они и что они значат?

Обновление:

После большого количества возни с этим кодомсоздает эти две записи в таблице TypeSpec.

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();
    }
}

Ответы [ 2 ]

4 голосов
/ 26 августа 2011

На оба токена TypeSpec в вашем примере ссылаются из IL в реализациях метода, а не из метаданных. Например, IL для одного из ваших методов выглядит так:

.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

Маркер TypeSpec используется для представления "! T" в ограниченном префиксе. Вы увидите аналогичную ссылку на другой токен TypeSpec в теле другого метода.

2 голосов
/ 27 августа 2011

Если вы используете ILDasm, вы можете получить хорошую разбивку методов, перейдите в View -> Meta Info -> select More Hex. Затем перейдите в View -> Meta Info -> Show!

Вот разбивка для второго метода:

    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)

Если прокрутить вниз, вы также увидите записи таблицы TypeSpec.

TypeSpec # 1 (1b000001)

TypeSpec : MVar!!0
Signature: 1e 00 

TypeSpec # 2 (1b000002)

TypeSpec : Var!0
Signature: 13 00 

То, что ILdasm показывает выше, это то, что VAR (13 00) является универсальным! T, передаваемым на уровне класса (универсальный параметр в определении типа), а MVAR (1e 00) является универсальным !! N, передаваемым на уровне метода ( универсальный параметр в определении метода).

Однако ... вы уже знаете, что у Ориона есть ваш ответ - записи в таблице TypeSpec используются в IL. Одна запись используется в одном методе, а другая - в другом методе. Вы можете увидеть это в ILdasm, когда посмотрите на методы:

    .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'

и

.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'

Таблица 0x1b - это TypeSpec, поэтому в следующих строках из вышеприведенных методов показано использование двух строк, которые вас интересуют:

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

и

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