Aquí es lo que quiero hacer:

  1. Ejecutar un programa de e inicializar las estructuras de datos.
  2. A continuación, compilar código adicional que se puede acceder/modificar las estructuras de datos existentes.
  3. Repita el paso 2 según sea necesario.

Quiero ser capaz de hacer esto con tanto C y C++ utilizando gcc (y eventualmente Java) en sistemas Unix (especialmente Linux y Mac OS X). La idea es, básicamente, implementar un read-eval-print loop para estos idiomas que compila las expresiones y las instrucciones y los utiliza para modificar las existentes estructuras de datos (algo que se hace todo el tiempo en lenguajes de secuencias de comandos). Estoy escribiendo esta herramienta en python, que genera la C/C++ archivos, pero esto no debería ser relevante.

He explorado hacer esto con bibliotecas compartidas, sino que aprendió que la modificación de las bibliotecas compartidas no afecta a los programas que ya están en ejecución. También he intentado usar memoria compartida, pero no podía encontrar una manera de cargar una función en el montón. También he considerado el uso de código de ensamblaje, pero no han intentado hacerlo.

Prefiero no utilizar cualquier otros compiladores gcc a menos que no hay absolutamente ninguna manera de hacerlo en gcc.

Si alguien tiene alguna idea o sabe cómo hacerlo, cualquier ayuda será apreciada.

  • Usted debe buscar en la llvm/clang. Pero un REPL para C o C++ suena como una gran tarea.
  • Algo que ver con la este?
  • Yo prefiero el uso real del lenguaje de secuencias de comandos, excepto que usted puede decir lo que es todo esto para
InformationsquelleAutor Matt | 2012-05-12

6 Comentarios

  1. 12

    Creo que usted puede ser capaz de lograr esto mediante las bibliotecas dinámicas y se carga en tiempo de ejecución (mediante dlopen y amigos).

    void * lib = dlopen("mynewcode.so", RTLD_LAZY);
    if(lib) {
        void (*fn)(void) = dlsym(lib, "libfunc");
    
        if(fn) fn();
        dlclose(lib);
    }

    Usted, evidentemente, tiene que ser de compilar el nuevo código a medida que avanza, pero si mantienes la sustitución de mynewcode.so creo que esto funcionará para usted.

    • La carga debe ser apoyado, no estoy seguro de que un de carga es compatible en todos los casos, sin embargo.
    • Voy a confesar que estoy ahora de un experto en tiempo de ejecución de la carga, pero el hombre de la página me lleva a creer que los símbolos son descargadas en dlclose (específicamente el RTLD_NODELETE bandera). Todo con un grano de sal, sin embargo,:).
  2. 13

    Hay una solución simple:

    1. crear una biblioteca propia de tener funciones especiales
    2. de carga creado biblioteca
    3. ejecutar las funciones de la biblioteca, pasar estructuras como función de las variables

    El uso de sus estructuras, usted tiene que incluir la misma archivos de encabezado como en la aplicación host.

    estructuras.h:

    struct S {
        int a,b;
    };

    main.cpp:

    #include <iostream>
    #include <fstream>
    #include <dlfcn.h>
    #include <stdlib.h>
    
    #include "structs.h"
    
    using namespace std;
    
    int main ( int argc, char **argv ) {
    
        //create own program
        ofstream f ( "tmp.cpp" );
        f << "#include<stdlib.h>\n#include \"structs.h\"\n extern \"C\" void F(S &s) { s.a += s.a; s.b *= s.b; }\n";
        f.close();
    
        //create library
        system ( "/usr/bin/gcc -shared tmp.cpp -o libtmp.so" );
    
        //load library        
        void * fLib = dlopen ( "./libtmp.so", RTLD_LAZY );
        if ( !fLib ) {
            cerr << "Cannot open library: " << dlerror() << '\n';
        }
    
        if ( fLib ) {
            int ( *fn ) ( S & ) = dlsym ( fLib, "F" );
    
            if ( fn ) {
                for(int i=0;i<11;i++) {
                    S s;
                    s.a = i;
                    s.b = i;
    
                    //use function
                    fn(s);
                    cout << s.a << " " << s.b << endl;
                }
            }
            dlclose ( fLib );
        }
    
        return 0;
    }

    de salida:

    0 0
    2 1
    4 4
    6 9
    8 16
    10 25
    12 36
    14 49
    16 64
    18 81
    20 100

    También puede crear mutable programa que se cambia en sí (el código fuente), volver a compilar sí mismo y, a continuación, sustituya la ejecución real con execv y ahorrar recursos con memoria compartida.

    • información muy útil pero, ¿cómo ir sobre la inclusión de la main.cpp en el tmp.cpp?
    • Okey, yo iba a editar la pregunta a responder, pero no es necesario 🙂 Usted no puede incluir los main.cpp en tmp. Si desea compartir algunos datos, entonces usted tiene que utilizar los encabezados (o escribir directamente a archivo) y el paso de las estructuras en la creación dinámica de la función 🙂
    • thnx! cuando se utiliza encabezados sin embargo los valores de las variables compartidas no son el mismo. así que al final tienen que pasar a la función. me pregunto si hay alguna manera de ir alrededor de pasar variables
    • Si usted incluir el encabezado en cpp, es lo mismo como si usted ha escrito su contenido en cpp. Así que al final termina con dos instancias de variables ( main.cpp y dinámica de la biblioteca ), pero si la u tuvo el encabezado(definición de variables) que se incluyen en dos objetos(cpp-s) en la misma biblioteca, luego se va a tirar error en la compilación. Tienes que usar «extern» de palabras clave en la cabecera, a decir del compilador, estas variables no se crea una instancia de objeto actual(cpp) y estará vinculado por el enlazador. Usted puede hacer que las variables ‘estática’, se creará una instancia privada en cada objeto, pero no compartir nada de todos modos.
  3. 4

    Aunque LLVM es ahora utilizado hoy en día la mayoría de sus optimizaciones y backend roles en la compilación, ya que su esencia es la Máquina Virtual de Bajo Nivel.

    LLVM puede JIT código, aunque los tipos de devolución puede ser bastante opaco, por lo que si usted está listo para envolver su propio código a su alrededor y no se preocupe demasiado acerca de los modelos que se van a tomar su lugar, puede ayudar a usted.

    Sin embargo en C y C++ no son muy amigables para este tipo de cosas.

  4. 3

    Esto se puede hacer portabilidad con OpenCL

    OpenCL es un ampliamente soportado estándar, utilizado principalmente para la descarga de los cálculos para hardware especializado, tales como la Gpu. Sin embargo, también funciona bien en las Cpu y de hecho se realiza en tiempo de ejecución recopilación de las C99-como el código como una de sus características básicas (esto es como el hardware de la portabilidad se logra). Las versiones más recientes (2.1+) aceptar también un gran subconjunto de C++14.

    Un ejemplo básico de dicha ejecución en tiempo de compilación & ejecución podría ser algo como esto:

    #ifdef __APPLE__
    #include<OpenCL/opencl.h>
    #else
    #include<CL/cl.h>
    #endif
    #include<stdlib.h>
    int main(int argc,char**argv){//assumes source code strings are in argv
        cl_int e = 0;//error status indicator
        cl_platform_id platform = 0;
        cl_device_id device = 0;
        e=clGetPlatformIDs(1,&platform,0);                                      if(e)exit(e);
        e=clGetDeviceIDs(platform,CL_DEVICE_TYPE_ALL,1,&device,0);              if(e)exit(e);
        cl_context context = clCreateContext(0,1,&device,0,0,&e);               if(e)exit(e);
        cl_command_queue queue = clCreateCommandQueue(context,device,0,&e);     if(e)exit(e);
        //the lines below could be done in a loop, assuming you release each program & kernel
        cl_program program = clCreateProgramWithSource(context,argc,(const char**)argv,0,&e);
        cl_kernel kernel = 0;                                                   if(e)exit(e);
        e=clBuildProgram(program,1,&device,0,0,0);                              if(e)exit(e);
        e=clCreateKernelsInProgram(program,1,&kernel,0);                        if(e)exit(e);
        e=clSetKernelArg(kernel,0,sizeof(int),&argc);                           if(e)exit(e);
        e=clEnqueueTask(queue,kernel,0,0,0);                                    if(e)exit(e);
        //realistically, you'd also need some buffer operations around here to do useful work
    }
  5. 2

    Si nada más funciona – en particular, si la onu-la carga de una biblioteca compartida termina por no ser compatibles con su plataforma en tiempo de ejecución, puede hacerlo de la manera difícil.

    1) sistema de uso de la() o lo que sea para ejecutar gcc o hacer o lo que sea para generar el código de

    2) cualquiera de enlace como un binario plano o análisis de cualquier formato (elf?) el vinculador salidas de su plataforma de ti mismo

    3) hazte con algún ejecutable páginas, ya sea por mmap()’ing un archivo ejecutable o hacer haciendo un mmap anónimo con el bit de ejecución establecido y copiar/desembalaje de su código (no todas las plataformas de atención acerca de que poco, pero vamos a suponer que usted tiene uno que hace)

    4) vaciar los datos y la instrucción almacena en caché (desde la coherencia entre los dos es que normalmente no garantizado)

    5) la llamada a través de un puntero a función o lo que sea

    Por supuesto, hay otra opción también – dependiendo del nivel de interacción que usted necesita, usted podría construir un programa independiente y lanzar y esperar por el resultado, o la horquilla off y poner en marcha y hablar por los tubos o sockets. Si esto se ajusten a sus necesidades, sería mucho menos complicado.

Dejar respuesta

Please enter your comment!
Please enter your name here