.NET9 FCall/QCall调用约定
内容提要
FCall/Qcall是托管与非托管之间的调用约定,双方需要一个契约,以弥合彼此的互相/单向调用。FCall用于托管调用非托管函数,而QCall用于托管调用非托管导出函数。
延伸解读
FCall 与 QCall 的适用场景
FCall 用于托管代码调用 CLR 内部非托管函数,如 GC.CollectionCount 通过 InternalCall 标记触发。QCall 则用于调用非托管导出函数,如 Buffer_MemMove 通过 DllImport 声明。两者都需在托管与非托管间建立调用契约,但 FCall 更强调与 CLR 内部实现的一致性,QCall 则遵循平台标准调用约定。
FCall 的宏机制与参数重排
FCall 通过 FCIMPL 系列宏实现,如 FCIMPL2 展开后包含 FCIMPL_PROLOG 和 FCIMPL_EPILOG。这些宏负责使用正确的调用约定、调整参数在堆栈或寄存器中的顺序,并处理未修饰名称的导出。这确保了托管代码与 CLR 原生代码在调用时参数传递和返回值处理的一致性。
非托管调用约定的差异与影响
非托管调用约定包括 thiscall、stdcall、cdecl 和 fastcall。thiscall 用寄存器传递 this 指针,stdcall 用于 Win32 API 且自身清理堆栈,cdecl 由调用者清理堆栈,fastcall 前几个参数用寄存器传递。这些差异直接影响参数传递顺序和堆栈清理责任,是理解 FCall/QCall 如何适配不同平台的基础。
Q&A
FCall和QCall的主要区别是什么?
FCall用于托管调用非托管函数,而QCall用于托管调用非托管导出函数。
非托管调用约定有哪些类型?
非托管调用约定有四种:thiscall、stdcall、cdecl和fastcall。
FCall是如何确保调用约定正确的?
FCall通过宏定义重新排序参数和返回值,确保调用约定的正确性。
什么是FCIMPL宏定义,它的作用是什么?
FCIMPL宏定义用于实现FCall,确保调用约定正确并处理参数的顺序。
stdcall调用约定的特点是什么?
stdcall一般用于win32 API,自身清理堆栈,从右往左传递参数。
QCall是如何在托管代码中使用的?
QCall一般使用导出标记extern,遵循平台标准进行托管调用非托管导出函数。