Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you dynamically compile and link/load C code into a C program?

Tags:

c

jit

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.

like image 495
Lance Avatar asked Dec 18 '22 16:12

Lance


1 Answers

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;
}
like image 194
dbush Avatar answered Dec 20 '22 06:12

dbush