我正在处理一个复杂的程序,它将有插件调用函数,但是这些函数的方法将在启动时被选择,并使用函数指针分配。
我希望在主可执行文件中有一些高效的包装器函数来调用适当的函数,而不是传递函数指针。
因为对于插件接口,调用约定将根据构建目标(使用宏)定义__cdecl
或__stdcall
,函数将声明为extern "C"
。
基本上,我希望能够在我的可执行文件中声明一个符号,插件可以根据需要加载。对于需要解决复杂科学问题的不同任务,解决这些任务的解决方案或方法的范围是如何的,这些解决方案或方法将存储在插件中,因此很容易添加新方法(不重新编译整个应用程序),这也使共享新方法变得更容易,因为任何具有基本代码的人都可以添加任何不需要自己体验的插件。
无论如何,我都可以使用这个概念,或者在加载插件时必须将函数映射传递给插件,但是函数映射的具体内容取决于加载的配置和插件,因此在加载插件之前,我不知道它是什么,这将是一个问题。因此,我的解决方案是将映射存储为主可执行文件中的一组全局变量,并通过包装器函数访问。
但是,这并不是直接的,因为函数具有调用约定,在调用后和返回之前涉及操作堆栈,在包装器上应该忽略这一点,它还应该为intel x386 ASM执行一个非相关的跳转x386,而不是为intel x386 ASM执行函数调用call
,而控制应该从跳转函数返回到调用代码而不是包装程序。但是,我需要C/C++代码来独立于编译器/平台/处理器。
下面是一个基本概念示例,用于测试我的想法并演示我想要做的事情:
C++代码(Microsoft C++ 2010 (特定))
#include <iostream>
void * pFunc;
int doit(int,int);
int wrapper(int, int);
int main() {
pFunc = (void*)doit;
std::cout << "Wrapper(2,3): " << wrapper(2,3) << std::endl;
std::cout << "doit(2,3): " << doit(2,3) << std::endl;
return 0; }
int doit(int a,int b) { return a*b; }
__declspec(naked) int wrapper(int, int) { __asm jmp pFunc }
代码经过测试才能正常工作,这两个调用都是输出6。
包装器和doit的ASM输出
PUBLIC ?wrapper@@YAHHH@Z ; wrapper
; Function compile flags: /Odtp
; COMDAT ?wrapper@@YAHHH@Z
_TEXT SEGMENT
___formal$ = 8 ; size = 4
___formal$ = 12 ; size = 4
?wrapper@@YAHHH@Z PROC ; wrapper, COMDAT
; File c:\users\glen fletcher\documents\visual studio 2010\projects\test_wrapper\test_wrapper.cpp
; Line 15
jmp DWORD PTR ?pFunc@@3PAXA ; pFunc
?wrapper@@YAHHH@Z ENDP ; wrapper
_TEXT ENDS
PUBLIC ?doit@@YAHHH@Z ; doit
; Function compile flags: /Ogtp
; COMDAT ?doit@@YAHHH@Z
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
?doit@@YAHHH@Z PROC ; doit, COMDAT
; Line 14
push ebp
mov ebp, esp
mov eax, DWORD PTR _a$[ebp]
imul eax, DWORD PTR _b$[ebp]
pop ebp
ret 0
?doit@@YAHHH@Z ENDP ; doit
; Function compile flags: /Ogtp
_TEXT ENDS
用于包装的非包装ASM
PUBLIC wrapper
_1$ = 8
_2$ = 12
_TEXT SEGMENT
wrapper PROC
push ebp
mov ebp, esp
mov eax, DWORD PTR _2$[ebp]
push eax
mov ecx, DWORD PTR _1$[ebp]
push ecx
call DWORD PTR pFunc
add esp, 8
pop ebp
ret 0
wrapper ENDP
_TEXT ENDS
如何以跨平台和跨编译器的方式生成原始代码??与编译器生成的带有epilog和prolog代码的C/C++函数的标准相反,备注也不想对处理器作出假设,因此不能执行单独的ASM文件,希望编译器只使用无条件跳转语句生成代码。
goto
不工作,因为pFunc是一个变量,而不是标签,甚至不确定它的goto
在函数之间是否能工作。
发布于 2013-11-15 03:03:21
我想出了解决问题的方法,而不是使用裸露的函数或传递函数指针的列表。
我可以传递一个指向函数指针结构的指针,即
struct Functions {
bool (AppAPI *logInfo(std::string,...)),
bool (AppAPI *logWarn(std::string,...)),
bool (AppAPI *logError(std::string,...)),
bool (AppAPI *registerFunction(std::string,void *))
...
} PluginFunctions;
for (int i = 0;i<plugins;i++) {
plugin[i].initialize(&PluginFunctions)
}
PluginFunctions.logInfo = LogInfo;
...
由于插件init函数将指针传递给结构,它可以存储这个指针,然后从内存中加载函数指针的当前值,结构只是内存中的指针表,函数指针可以在结构传递到插件之后设置,并且它仍然更新插件。
https://stackoverflow.com/questions/19970859
复制相似问题