Можете ли вы динамически скомпилировать и связать / загрузить C-код в C-программу? - PullRequest
2 голосов
/ 01 июля 2019

Я читал о eval в C , и имеет смысл, что если вы напишите синтаксический анализатор / оценщик строки C, вы можете просто сопоставить его с конкретными функциями в вашей основной программе на C.Но на самом деле он не помещает его в исполняемую память из того, что я понимаю, как это делает JIT-компилятор .Я не совсем понимаю JIT-компиляторы (я никогда не создавал один), но я понимаю суть.

Так что мне интересно, если вы можете создать своего рода JIT-компилятор в C, не выполняя слишком много работыРазбор строк C и преобразование в AST и еще много чего.В принципе, можете ли вы сделать как в JavaScript и динамически создать функцию (в C), такую, что эта функция точно такая же, как любая другая функция C (то есть она скомпилирована непосредственно в исполняемый машинный код в исполняемом файлеэто часть программы).

Если это невозможно сделать, вторым подходом будет динамическая загрузка импорта / файлов / модулей на С.Таким образом, вы запускаете процесс, который говорит компилятору clang скомпилировать некоторые библиотечные функции, и после того, как это сделано, не останавливая текущую программу, он связывает / присоединяет эту новую библиотеку программы к себе, и поэтому может выполнить код таким образом .

Если это невозможно, возможно, можно просто перекомпилировать программу в фоновом режиме, а затем заменить текущую программу новой программой, которая загружается с нуля.Это было бы просто очень примитивно.

Попытка выяснить, есть ли у вас структуры для собственного типа данных пользовательской функции в C, как вы можете затем выполнить эту функцию в C наиболее оптимизированным способом.

Ответы [ 3 ]

4 голосов
/ 01 июля 2019

В системах POSIX (Linix, Mac, UNIX) у вас есть функции dlopen и dlsym, с которыми вы можете работать.Эти функции можно использовать для загрузки разделяемой библиотеки во время выполнения и выполнения из нее функции.

Что касается создания библиотеки, проще всего было бы написать соответствующий исходный код в файл,запустите gcc в отдельном процессе для его компиляции, затем используйте dlopen / dlsym для запуска содержащихся в нем функций.

Например:

#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 голосов
/ 01 июля 2019

Существует также компилятор Tiny C, который можно использовать в качестве библиотеки, с помощью которой вы можете скомпилировать программу на лету и вызывать функции во вновь скомпилированном коде из существующего кода , не прибегая к динамическая загрузка библиотеки.

Код не будет максимально оптимизированным из возможных C, но он также не так уж и плох.

Пример в этом ответе .

0 голосов
/ 01 июля 2019

В дополнение к маршруту dlload некоторые средства оценки выражений и инструменты математического ядра SIMD генерируют динамический код в блок памяти, который становится исполняемым с помощью mprotect (2) и PROT_EXEC.

Хотя обычно это не HLL, как C, а просто математические выражения. Если ваши требования довольно просты, это может быть маршрут. Обычно он используется для простых функций, которые чувствительны к скорости из-за их использования, например 2D / 3D графики или преобразования изображений

...