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

99封情书 提交于 2019-11-30 05:16:22
Hans Passant

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)*

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?

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!