dte*_*ech 54 c++ runtime function dynamic
C++是一种静态的编译语言,在编译期间解析模板等等......
但是有可能在运行时创建一个函数,这在源代码中没有描述,并且在编译期间还没有转换为机器语言,因此用户可以向它投入源中没有预料到的数据吗?
我知道这不可能以一种简单的方式发生,但肯定必须是可能的,有很多编程语言没有被编译并且动态创建那些用C或C++实现的东西.
也许如果创建了所有原始类型的工厂,以及将它们组织成更复杂的对象(如用户类型和函数)的合适数据结构,这是可以实现的吗?
欢迎提供有关该主题的任何信息以及指向在线资料的链接.谢谢!
编辑:我知道这是可能的,它更像是我对实现细节感兴趣:)
Wal*_*ter 44
是的,当然,没有其他答案中提到的任何工具,只是简单地使用C++编译器.
只需在你的C++程序中执行这些步骤(在linux上,但在其他操作系统上必须类似)
ofstreamsystem("c++ /tmp/prog.cc -o /tmp/prog.so -shared -fPIC"); dlopen()Jay*_*Jay 38
您也可以直接将字节码提供给函数,并将其作为函数类型传递,如下所示.
例如
byte[3] func = { 0x90, 0x0f, 0x1 }
*reinterpret_cast<void**>(&func)()
Run Code Online (Sandbox Code Playgroud)
Mil*_*lan 16
是的,JIT编译器会一直这样做.它们分配一块由OS赋予特殊执行权限的内存,然后用代码填充它并将指针强制转换为函数指针并执行它.很简单.
编辑:以下是如何在Linux中执行此操作的示例:http://burnttoys.blogspot.de/2011/04/how-to-allocate-executable-memory-on.html
下面是基于前面提到的方法的C++运行时编译示例(将代码写入输出文件,编译通过system(),加载通过dlopen()和dlsym()).另请参阅相关问题中的示例.这里的区别在于它动态编译类而不是函数.这是通过maker()向要动态编译的代码添加C样式函数来实现的.参考文献:
该示例仅适用于Linux(Windows具有LoadLibrary和GetProcAddress功能),并且需要在目标计算机上使用相同的编译器.
baseclass.h
#ifndef BASECLASS_H
#define BASECLASS_H
class A
{
protected:
double m_input; // or use a pointer to a larger input object
public:
virtual double f(double x) const = 0;
void init(double input) { m_input=input; }
virtual ~A() {};
};
#endif /* BASECLASS_H */
Run Code Online (Sandbox Code Playgroud)
main.cpp中
#include "baseclass.h"
#include <cstdlib> // EXIT_FAILURE, etc
#include <string>
#include <iostream>
#include <fstream>
#include <dlfcn.h> // dynamic library loading, dlopen() etc
#include <memory> // std::shared_ptr
// compile code, instantiate class and return pointer to base class
// https://www.linuxjournal.com/article/3687
// http://www.tldp.org/HOWTO/C++-dlopen/thesolution.html
// https://stackoverflow.com/questions/11016078/
// https://stackoverflow.com/questions/10564670/
std::shared_ptr<A> compile(const std::string& code)
{
// temporary cpp/library output files
std::string outpath="/tmp";
std::string headerfile="baseclass.h";
std::string cppfile=outpath+"/runtimecode.cpp";
std::string libfile=outpath+"/runtimecode.so";
std::string logfile=outpath+"/runtimecode.log";
std::ofstream out(cppfile.c_str(), std::ofstream::out);
// copy required header file to outpath
std::string cp_cmd="cp " + headerfile + " " + outpath;
system(cp_cmd.c_str());
// add necessary header to the code
std::string newcode = "#include \"" + headerfile + "\"\n\n"
+ code + "\n\n"
"extern \"C\" {\n"
"A* maker()\n"
"{\n"
" return (A*) new B(); \n"
"}\n"
"} // extern C\n";
// output code to file
if(out.bad()) {
std::cout << "cannot open " << cppfile << std::endl;
exit(EXIT_FAILURE);
}
out << newcode;
out.flush();
out.close();
// compile the code
std::string cmd = "g++ -Wall -Wextra " + cppfile + " -o " + libfile
+ " -O2 -shared -fPIC &> " + logfile;
int ret = system(cmd.c_str());
if(WEXITSTATUS(ret) != EXIT_SUCCESS) {
std::cout << "compilation failed, see " << logfile << std::endl;
exit(EXIT_FAILURE);
}
// load dynamic library
void* dynlib = dlopen (libfile.c_str(), RTLD_LAZY);
if(!dynlib) {
std::cerr << "error loading library:\n" << dlerror() << std::endl;
exit(EXIT_FAILURE);
}
// loading symbol from library and assign to pointer
// (to be cast to function pointer later)
void* create = dlsym(dynlib, "maker");
const char* dlsym_error=dlerror();
if(dlsym_error != NULL) {
std::cerr << "error loading symbol:\n" << dlsym_error << std::endl;
exit(EXIT_FAILURE);
}
// execute "create" function
// (casting to function pointer first)
// https://stackoverflow.com/questions/8245880/
A* a = reinterpret_cast<A*(*)()> (create)();
// cannot close dynamic lib here, because all functions of the class
// object will still refer to the library code
// dlclose(dynlib);
return std::shared_ptr<A>(a);
}
int main(int argc, char** argv)
{
double input=2.0;
double x=5.1;
// code to be compiled at run-time
// class needs to be called B and derived from A
std::string code = "class B : public A {\n"
" double f(double x) const \n"
" {\n"
" return m_input*x;\n"
" }\n"
"};";
std::cout << "compiling.." << std::endl;
std::shared_ptr<A> a = compile(code);
a->init(input);
std::cout << "f(" << x << ") = " << a->f(x) << std::endl;
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
产量
$ g++ -Wall -std=c++11 -O2 -c main.cpp -o main.o # c++11 required for std::shared_ptr
$ g++ -ldl main.o -o main
$ ./main
compiling..
f(5.1) = 10.2
Run Code Online (Sandbox Code Playgroud)
看看libtcc;它简单、快速、可靠并且适合您的需要。每当我需要“即时”编译 C 函数时,我都会使用它。
在存档中,您将找到文件examples/libtcc_test.c,它可以为您提供良好的开端。这个小教程也可能对您有所帮助:http : //blog.mister-muffin.de/2011/10/22/discovering-tcc/
#include <stdlib.h>
#include <stdio.h>
#include "libtcc.h"
int add(int a, int b) { return a + b; }
char my_program[] =
"int fib(int n) {\n"
" if (n <= 2) return 1;\n"
" else return fib(n-1) + fib(n-2);\n"
"}\n"
"int foobar(int n) {\n"
" printf(\"fib(%d) = %d\\n\", n, fib(n));\n"
" printf(\"add(%d, %d) = %d\\n\", n, 2 * n, add(n, 2 * n));\n"
" return 1337;\n"
"}\n";
int main(int argc, char **argv)
{
TCCState *s;
int (*foobar_func)(int);
void *mem;
s = tcc_new();
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
tcc_compile_string(s, my_program);
tcc_add_symbol(s, "add", add);
mem = malloc(tcc_relocate(s, NULL));
tcc_relocate(s, mem);
foobar_func = tcc_get_symbol(s, "foobar");
tcc_delete(s);
printf("foobar returned: %d\n", foobar_func(32));
free(mem);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果您在使用图书馆时遇到任何问题,请在评论中提出问题!