C++ 如何从C++;动态的?
要求:对于某个项目,我们有独特的要求。该应用程序支持一种表达式语言,允许用户定义自己的复杂表达式,这些表达式可以在运行时(每秒数百次)进行计算,并且需要在机器级别执行以提高性能 工作:我们的表达式解析器完美地将脚本翻译成相应的汇编语言例程。我们通过静态链接C测试程序生成的对象文件来检查它,它们生成正确的结果。 由于客户端可以随时更改脚本,我们的程序(在运行时)检测到更改,调用解析器,解析器生成相应的汇编例程。然后,我们从后端调用汇编程序来创建目标代码 问题 如何从C++程序动态调用这个汇编例程 (装载机)C++ 如何从C++;动态的?,c++,assembly,dynamic,linker,C++,Assembly,Dynamic,Linker,要求:对于某个项目,我们有独特的要求。该应用程序支持一种表达式语言,允许用户定义自己的复杂表达式,这些表达式可以在运行时(每秒数百次)进行计算,并且需要在机器级别执行以提高性能 工作:我们的表达式解析器完美地将脚本翻译成相应的汇编语言例程。我们通过静态链接C测试程序生成的对象文件来检查它,它们生成正确的结果。 由于客户端可以随时更改脚本,我们的程序(在运行时)检测到更改,调用解析器,解析器生成相应的汇编例程。然后,我们从后端调用汇编程序来创建目标代码 问题 如何从C++程序动态调用这个汇编例程
我们不应该调用C++编译器来与装载器链接,因为加载器已经有其他子程序运行,我们不能把加载器关闭,重新编译,然后执行新的加载器程序。p>
我尝试在线搜索解决方案,但每次搜索结果都充斥着.NET程序集动态调用。我们的应用程序与.NET没有任何关系。正如评论所指出的,
LoadLibrary
(Windows)和dlopen
(Linux/POSIX)是迄今为止最简单的解决方案。它们专门用于动态加载代码。同样重要的是,它们都允许卸载,并且有一些函数可以通过名称获取函数入口点。您可以动态地执行此操作。我将以linux案例为例。由于解析器工作正常并生成机器代码,您应该能够生成.so(对于linux)或.dll(对于windows)。
接下来,将库加载为
handle = dlopen(so_file_name, RTLD_LAZY);
下一个get函数指针
func = dlsym(handle, "function_name");
那么您应该能够以func()的形式执行它
您需要试验的一件事(如果您没有得到期望的结果)是关闭并打开so文件或dll文件(您只需要在需要时执行,否则可能会降低性能)首先,是“生成的”方法(在Linux上;我的答案集中在Linux上,但可以通过一些努力适应Windows;您可以使用许多平台框架,如or或Glib from;然后使用所有包装插件加载功能,如dlopendlopen
,以及一个通用API,您可以在Windows、Linux、MacOSX和Android上使用):
- 在一些文件<代码> /tMP/ Guangdiabd1.c/Cu>中生成C(或汇编)代码(甚至可以使用标准C++容器生成C++代码,但是编译速度会慢得多;注意发出和使用<代码>外部”C“< /代码>函数;读取”。(而且可能比生成汇编代码更好、更具可移植性)
- 运行(使用
+fork
+execve
,或简单地使用waitpid
)通过运行system
命令,将生成的文件编译成共享对象gcc-fPIC-Wall-O/tmp/generated01.c-shared-O/tmp/tmp/generated01.c-generated01.so
;实际上需要get,因此需要使用/tmp/generated01.so
标志。如果在生成的汇编代码上使用-fPIC
,则需要改进汇编生成器发出PIC代码dlopen
新的dlopen
(使用),请参见;您甚至可以/tmp/generated01.so
删除现在无用的生成的C文件
/tmp/generated01.C
获取指向生成代码的函数指针的相关符号,请参见;您的应用程序只需使用这些函数指针调用生成的代码即可dlsym
- 当您确定不需要它的任何函数并且没有调用框架使用它时,您可以
该共享对象库(但您可以通过根本不调用dlclose
来泄漏一些地址空间)dlclose
dlopen
一百万个不同的共享对象),并且实际上甚至是兼容的(即使在发出C代码时!)由于大多数情况下,生成的/tmp/generated01.c
非常小(例如,最多几百行),因此在大多数当前台式机、笔记本电脑和服务器上,生成的/tmp/generated01.c
将非常快地生成和编译(通过gcc
等)在Linux上,这种插件方法通常需要将主应用程序链接到-rdynamic
(以便dlopen
-ed插件可以从主应用程序引用和调用函数)
然后,其他方法可以是使用一些库,比如
- (这会非常快地发出缓慢的机器代码-因此JIT发出时间非常短,但生成的代码运行缓慢,因为它非常未优化)
- ;它特定于x86-64,使您能够生成单个x86-64机器指令
- GNU可用于多种平台,并为其他平台提供“解释器”模式
- (编译器的一部分,可用作JIT库)
- (新的JIT库前端到)
gcc-fPIC-O1
或-O2
编译生成的等效C代码(但通常会慢2到5倍!);最后两个元素(LLVM和GCCJIT)是基于编译器的:因此他们能够优化并发出高效的代码,而牺牲较慢的JIT代码发出速度。所有JIT库都能够(如dlsym对插件所做的)向新JIT构造的函数提供函数指针