Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何从C++;动态的?_C++_Assembly_Dynamic_Linker - Fatal编程技术网

C++ 如何从C++;动态的?

C++ 如何从C++;动态的?,c++,assembly,dynamic,linker,C++,Assembly,Dynamic,Linker,要求:对于某个项目,我们有独特的要求。该应用程序支持一种表达式语言,允许用户定义自己的复杂表达式,这些表达式可以在运行时(每秒数百次)进行计算,并且需要在机器级别执行以提高性能 工作:我们的表达式解析器完美地将脚本翻译成相应的汇编语言例程。我们通过静态链接C测试程序生成的对象文件来检查它,它们生成正确的结果。 由于客户端可以随时更改脚本,我们的程序(在运行时)检测到更改,调用解析器,解析器生成相应的汇编例程。然后,我们从后端调用汇编程序来创建目标代码 问题 如何从C++程序动态调用这个汇编例程

要求:对于某个项目,我们有独特的要求。该应用程序支持一种表达式语言,允许用户定义自己的复杂表达式,这些表达式可以在运行时(每秒数百次)进行计算,并且需要在机器级别执行以提高性能

工作:我们的表达式解析器完美地将脚本翻译成相应的汇编语言例程。我们通过静态链接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;然后使用所有包装插件加载功能,如dlopen
dlopen
,以及一个通用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
    命令,将生成的文件编译成共享对象
    /tmp/generated01.so
    ;实际上需要get,因此需要使用
    -fPIC
    标志。如果在生成的汇编代码上使用
    dlopen
    ,则需要改进汇编生成器发出PIC代码
  • 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库前端到)
大体上说,该列表中的第一个元素能够相当快地发出JIT机器代码,但该代码的运行速度不如使用
gcc-fPIC-O1
-O2
编译生成的等效C代码(但通常会慢2到5倍!);最后两个元素(LLVM和GCCJIT)是基于编译器的:因此他们能够优化并发出高效的代码,而牺牲较慢的JIT代码发出速度。所有JIT库都能够(如dlsym
对插件所做的)向新JIT构造的函数提供函数指针