问题
I read about eval in C, and it makes sense that if you write a C string parser/evaluator, you can just map it to specific functions in your main C program. But it doesn't actually place it into executable memory from what I understand, like a JIT compiler seems to do. I don't fully understand JIT compilers (I never made one) but I get the gist.
So what I'm wondering is if you can create sort of a JIT compiler in C without doing too much work of parsing C strings and converting to ASTs and whatnot. Basically, can you do like in JavaScript and dynamically create a function (in C), such that that function is exactly the same as any other C function (i.e. it is compiled directly into executable machine code in the executable part of the program sort of thing).
If it's not possible to do that, a second approach would be to dynamically load C imports/files/modules. So you spin off a process that tells the clang compiler to compile some library function(s), and after it's done, without stopping the current program, it links/attaches that new program library to itself, and so can execute the code that way.
If that's not possible, maybe an option is to simply recompile the program in the background, then swap the current program with the new program which boots up from scratch. That would just be very primitive though.
Trying to figure out if you have some structs for your own custom function datatype in C, how you can then execute that function in C in the most optimized way.
回答1:
On POSIX systems (Linix, Mac, UNIX) you have the dlopen
and dlsym
functions you can work with. These functions can be used to load a shared library at run time and execute a function from it.
As far as creating a library, the simplest thing to do would be to write the relevant source code to a file, run gcc in a separate process to compile it, then use dlopen
/dlsym
to run the functions it contains.
For example:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
const char *libsrc =
"#include <stdio.h>\n"
"\n"
"void f1()\n"
"{\n"
" printf(\"in f1\\n\");\n"
"}\n"
"\n"
"int add(int a, int b)\n"
"{\n"
" return a+b;\n"
"}\n";
int main()
{
FILE *libfile = fopen("mylib.c", "w");
fputs(libsrc, libfile);
fclose(libfile);
system("gcc -fPIC -shared -g -Wall -Wextra -o libmylib.so mylib.c");
void *lib = dlopen("libmylib.so", RTLD_NOW);
if (!lib) {
printf("dlopen failed: %s\n", dlerror());
return 1;
}
void (*f)() = dlsym(lib, "f1");
if (f) {
f();
} else {
printf("dlsym for f1 failed: %s\n", dlerror());
}
int (*a)(int, int) = dlsym(lib, "add");
if (a) {
int x = a(2,3);
printf("x=%d\n", x);
} else {
printf("dlsym for add failed: %s\n", dlerror());
}
dlclose(lib);
return 0;
}
回答2:
There is also the Tiny C compiler that can be used as a library, with which you can compile a program on the fly and call the functions within the newly compiled code from the existing code without having to resort to dynamic library loading.
The code will not be the most optimized C possible, but it is not too bad either.
An example in this answer.
回答3:
In addition to the dlload route, some expression evaluators and SIMD math kernel tools generate dynamically code into a memory block that is made executable with mprotect(2) and PROT_EXEC.
Though that usually isn't a HLL like C, but just simple math expressions. If your requirements are fairly simple that could be a route. Typically it is used for simple functions that are speed sensitive due to their usage in e.g. 2D/3D plots or image transformations
来源:https://stackoverflow.com/questions/56829292/can-you-dynamically-compile-and-link-load-c-code-into-a-c-program