在(Visual)C ++中调用动态创建函数的约定

时间:2011-11-26 16:09:44

标签: c++ c visual-c++ x86

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

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).aspxhttp://en.wikipedia.org/wiki/X86_calling_conventions#cdecl将参数放在堆栈上,但是当我查看生成的汇编时,参数将被移动到EAX寄存器。

我想绝对肯定这些论据是如何准备的。那么我是否忽略了cdecl或Visual C ++优化调用的内容,如果是这样,我该如何确保它不会发生呢?

致以最诚挚的问候,Lasse Espeholt

2 个答案:

答案 0 :(得分:5)

EAX注册为used for the return value of the function。您在评论中说明了您正在使用/Gd进行编译,因此该函数将使用__cdecl。在我看来,使用明确的pfunc标记函数类型__cdecl的声明是有意义的,这样就不会有混淆和不匹配的空间。

当然,没有什么能阻止你使用编译器支持的其他调用约定之一。最重要的一点是,无论您采用何种调用约定,都应该明确指定函数指针的调用约定,因为编译器只负责接口的一半。

答案 1 :(得分:2)

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

如果您想在运行时生成机器代码,请考虑使用GNU lightning,DotGnu的libjitLLVM。 LuaJit的dynasm等你也可以在foo.c中生成C代码,通过分配gcc -fPIC -shared foo.c -o foo.so命令来编译它,dlopen("./foo.so", RTLD_GLOBAL)(和Windows具有相同的能力)

相关问题