【发布时间】:2011-11-26 16:09:44
【问题描述】:
我使用以下类型在运行时创建新函数:
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
【问题讨论】:
-
我很好奇你用这种技术解决了什么问题。
-
我不是MSVC,但你不能在函数指针类型中嵌入调用约定吗?
-
@KerrekSB:比起联合技巧,我更担心使用一些动态填充的二进制代码运行函数。前者更加“未定义”。 ;)
-
@JohnZwinck 和其他人。我正在开发一个迷你 JIT 编译器,有没有更好的方法呢?
-
@lasseespeholt:是的,当然:声明函数指针:
pfunc f;,然后获取指向其内存的字符指针:char * pf = reinterpret_cast<char*>(&f);,然后用 that 填充正确的值。 (将指针转换为 char 指针显然是 not 类型的双关语。)这并不意味着函数调用本身就有意义;只是你的建设是宽恕的。
标签: c++ c visual-c++ x86