What is the (fnptr)* type and how to create it?

前端 未结 3 1091
一个人的身影
一个人的身影 2020-12-29 11:02

The following IL code creates a Type instance named (fnptr)* (token 0x2000000 - invalid, module mscorlib.dll).

ldtoken method void* ()*
call cla         


        
相关标签:
3条回答
  • 2020-12-29 11:48

    Not sure where you're seeing the FNPTR being declared.

    For this code:

    .assembly extern mscorlib {}
    
    .assembly Test
    {
        .ver 1:0:1:0
    }
    .module test.exe
    
    .method static void main() cil managed
    {
        .maxstack 1
        .entrypoint
    
        ldtoken method void* ()*
        call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    
        ldtoken method void* ()
        call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    
        ret
    }
    

    ILASM (4.5.22.0) outputs the following:

    .method privatescope static void  main$PST06000001() cil managed
    {
      .entrypoint
      // Code size       21 (0x15)
      .maxstack  1
      IL_0000:  ldtoken    method void *()*
      IL_0005:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
      IL_000a:  ldtoken    method void *()
      IL_000f:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
      IL_0014:  ret
    } // end of method 'Global Functions'::main
    

    Update #1:

    Perhaps I am being dense here, but I am not seeing FNPTR being generated from this code:

    typeof(StringBuilder).ToString();
    

    The IL looks like this:

    IL_0000:  nop
    IL_0001:  ldtoken    [mscorlib]System.Text.StringBuilder
    IL_0006:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    IL_000b:  callvirt   instance string [mscorlib]System.Object::ToString()
    IL_0010:  pop
    IL_0011:  ret
    

    The Type.ToString() call is a callvirt operation since ToString() is a virtual method.

    Virtual functions are usually manifested as structs of function pointers which would, I guess, result in a FNPTR being emitted. If you omit the * in ()* resulting in (), you're now describing a function, not a function pointer.

    What version of .NET are you using when you see the FNPTR? What are you using to extract the IL?

    0 讨论(0)
  • 2020-12-29 11:57

    It is possible to load the signature of a pointer to a function pointer:

    public static unsafe Type GetTypeFromFieldSignature(byte[] signature, Type declaringType = null)
    {
        declaringType = declaringType ?? typeof(object);
        Type sigtype = typeof(Type).Module.GetType("System.Signature");
        Type rtype = typeof(Type).Module.GetType("System.RuntimeType");
        var ctor = sigtype.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new[]{typeof(void*), typeof(int), rtype}, null);
        fixed(byte* ptr = signature)
        {
            object sigobj = ctor.Invoke(new object[]{(IntPtr)ptr, signature.Length, declaringType});
            return (Type)sigtype.InvokeMember("FieldType", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty, null, sigobj, null);
        }
    }
    
    var fnptrPtr = GetTypeFromFieldSignature(new byte[]{6, 15, 27, 0, 0, 1});
    

    6 is field, 15 is pointer, 27 is function pointer and 0, 0, 1 is a method signature without return or parameters.

    0 讨论(0)
  • 2020-12-29 11:59

    I have no real idea what you are asking and why you think there is anything wrong. (fnptr)* is the type name of a pointer to an unmanaged function pointer. That it gets special treatment in the CLR is indeed odd, I suspect it is an archeological artifact. Dating back to a time before .NET and before delegates were invented. The CLR started life as the "universal runtime" in Project 42, a failed project before .NET.

    Maybe some C++/CLI code to demonstrate how to generate one is useful, shows you how to create it:

    #include "stdafx.h"
    
    using namespace System;
    
    typedef void (*functionPointer)(int);
    
    ref class Example {
    public:
        functionPointer* fp;
    };
    
    int main(array<System::String ^> ^args)
    {
        auto field = Example::typeid->GetField("fp");
        auto name = field->FieldType->FullName; 
        Console::WriteLine(name);
        return 0;
    }
    

    Output: (fnptr)*

    0 讨论(0)
提交回复
热议问题