c++中动态创建函数的调用约定

Calling convention for dynamically created function in (Visual) C++

本文关键字:调用 约定 函数 创建 动态 c++      更新时间:2023-10-16

我使用以下类型在运行时创建一个新函数:

typedef int (*pfunc)(int);
union funcptr {
  pfunc x;
  byte* y;
};

这使我能够在y中编写指令,然后像这样调用函数:

byte* p = (byte*)VirtualAllocEx(GetCurrentProcess(), 0, 1<<16, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
// Write some instructions to p
funcptr func;
func.y = p;
int ret = func.x(arg1); // Call the generated function

了解c++如何准备参数(调用约定)是至关重要的,因此我已经查看了项目属性(Visual c++),我可以看到它使用__cdecl。它应该根据:http://msdn.microsoft.com/en-us/library/aa271989(v=vs.60).aspx和http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl将参数放在堆栈上,但是当我查看生成的程序集时,参数被移动到EAX寄存器。

我想绝对确定参数是如何准备的。所以我忽略了一些关于cdecl或Visual c++优化调用,如果是这样,我如何确保它不会发生?

向Lasse Espeholt致以最诚挚的问候

EAX寄存器用于该函数的返回值。您在注释中声明您正在使用/Gd进行编译,因此该函数将使用__cdecl。尽管如此,在我看来,用显式的__cdecl标记函数类型pfunc的声明是有意义的,这样就不会有混淆和不匹配的余地。

当然,没有什么可以阻止您使用编译器支持的其他调用约定之一。最重要的一点是,无论您选择什么调用约定,都应该显式指定函数指针的调用约定,因为编译器只负责接口的一半。

至少在Linux上,您可能希望使用libffi(外部函数接口),它甚至被移植到其他系统(包括Windows)。

如果你想在运行时生成机器码,考虑使用GNU闪电,DotGnu的libjit, LLVM。你也可以生成C代码到foo.c,通过gcc -fPIC -shared foo.c -o foo.so命令和dlopen("./foo.so", RTLD_GLOBAL)(和Windows有同等的能力)来编译它