【问题标题】:How to find TypeSpec of generic argument如何找到泛型参数的 TypeSpec
【发布时间】:2019-02-26 15:03:37
【问题描述】:

一些初步信息

给定以下 C# 函数:

public static void func<T>(T t)
{
    System.Console.WriteLine(t);
}

编译成如下CIL:

.method public hidebysig static void  func<T>(!!T t) cil managed
{
    ldarg.0
    box        !!T
    call       void [mscorlib]System.Console::WriteLine(object)
    ret
}

上述方法的签名是10 01 01 01 1E 00,其中:

10 - 调用约定 (IMAGE_CEE_CS_CALLCONV_GENERIC) 01 - 函数泛型参数计数(为 1) 01 - 函数参数计数(为 1) 01 - 返回类型 (ELEMENT_TYPE_VOID) 1E - 第一个参数类型 (ELEMENT_TYPE_MVAR) 00 - 上述 MVAR 的索引(为 0)

另请参阅以下指令及其实际字节码:

盒子 !!T - 8C 1B000001

1B000001 指向 TypeSpec 表中的第一个条目,该条目指向 blob 02 1E 00,其中:

02 - 斑点长度 1E - 类型类型 (ELEMENT_TYPE_MVAR) 00 - 上述 MVAR 的索引(为 0)

如我们所见,方法签名以描述性方式包含泛型参数,而我们拥有实际的类型签名。
但是,当使用需要 TypeDef/Ref/Spec 的 OpCode 时,会提供 TypeSpec,并且 TypeSpec 指向带有类型信息的签名。


所以我的问题是:
我正在编写一个执行一些 IL 重写的分析器,并且给定函数签名,我想将一些 OpCodes 添加到将使用参数进行操作的函数体中。

使用IMetaDataImport2 接口,如何获取给定泛型参数所需的TypeSpec 令牌?

我可以看到 2 个选项:

  1. 遍历 EnumTypeSpecs 直到找到匹配的签名
  2. 使用IMetaDataEmit接口创建新的TypeSpec

但是,出于显而易见的原因,我想避免这两个选项并选择更明智的选择。

【问题讨论】:

    标签: .net generics profiling instrumentation cil


    【解决方案1】:

    所以我最终接受了我的第一个建议。
    我想这并不理想,但它确实有效。

    这里是代码,如果有人感兴趣(省略错误处理):

    HCORENUM typeSpecEnum = NULL;
    mdTypeSpec typeSpec = mdTypeSpecNil;
    ULONG outNum = -1;
    
    // Loop through enum
    while (true)
    {
        // Get next enum
        HRESULT hr = pMetadataImport->EnumTypeSpecs(&typeSpecEnum, &typeSpec, 1, &outNum);
        if (hr == S_FALSE && outNum == 0) // According to doc, this means no more. End loop
            break;
    
        // Get the signature of this typespec
        PCCOR_SIGNATURE curSpecSig = NULL;
        ULONG curSpecSigLen = -1;
        pMetadataImport->GetTypeSpecFromToken(typeSpec, &curSpecSig, &curSpecSigLen);
    
        if (curSpecSigLen == <my_len> && memcmp(curSpecSig, <my_sig>, <my_len>) == 0)
            ; // Token found
        else
            typeSpec = mdTypeSpecNil; // Reset and goto next token
    }
    
    pMetadataImport->CloseEnum(typeSpecEnum); // Don't forget to close enum
    

    【讨论】:

      猜你喜欢
      • 2020-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-06
      • 1970-01-01
      相关资源
      最近更新 更多