2012-08-27 19 views
6

Supongamos que tengo un archivo C sin dependencia externa, y solo la sección de datos const. Me gustaría compilar este archivo, y luego obtener un blob binario que puedo cargar en otro programa, donde la función se utilizaría a través de un puntero de función.Archivo de objeto a código binario

Tomemos un ejemplo, aquí es un módulo binario fictionnal, f1.c

static const unsigned char mylut[256] = { 
    [0 ... 127] = 0, 
    [128 ... 255] = 1, 
}; 

void f1(unsigned char * src, unsigned char * dst, int len) 
{ 
    while(len) { 
     *dst++ = mylut[*src++]; 
     len--; 
    } 
} 

me gustaría compilarlo a f1.o, entonces f1.bin, y utilizar de esta manera en Prog .c

int somefunc() { 
    unsigned char * codedata; 
    f1_type_ptr f1_ptr; 
    /* open f1.bin, and read it into codedata */ 

    /* set function pointer to beginning of loaded data */ 
    f1_ptr =(f1_type_ptr)codedata; 

    /* call !*/ 
    f1_ptr(src, dst, len); 
} 

Supongo que pasar de f1.c a f1.o implica -fPIC para obtener la independencia de posición. ¿Cuáles son las banderas o la secuencia de comandos del enlazador que puedo usar para pasar de f1.o a f1.bin?

Aclaración:

Sé acerca de la vinculación dinámica. el enlace dinámico no es posible en este caso. El paso de enlace debe ser puntero func de conversión a datos cargados, si es posible.

Supongamos que no hay compatibilidad con el sistema operativo. Si pudiera, me gustaría, por ejemplo, escribir f1 en el ensamblaje con la dirección relacionada con PC.

+0

¿Conoce que puede utilizar archivos de objetos compartidos? Usted compila su archivo .c en .so, luego lo carga 'dlopen()' en su programa, y ​​obtiene el puntero de función 'dlsym()' para la función. Entonces puedes llamarlo. –

+0

Olvidémonos de la vinculación libc y dinámica – shodanex

+0

¿Desea que la thingie 'f1.bin' se cargue dinámicamente (es decir, en tiempo de ejecución)? Luego, debe compilar una biblioteca compartida y usar ldopen() + ldsym() u otro cargador de módulos (como gmodule). Tratar de hacerlo de otra forma es probable que sea difícil y se rechace debido a posibles amenazas a la seguridad (ejecutar segmento de datos, etc.). –

Respuesta

2

Usted debe considerar la construcción de una biblioteca compartida (.dll para las ventanas, o .so para Linux).

Construir el lib así:

gcc -c -fPIC test.c 
gcc -shared test.o -o libtest.so 

Si desea cargar la biblioteca dinámica a partir de su código, echar un vistazo a las funciones dlopen (3) y dlsym (3).

O si desea vincular la biblioteca en el momento de la compilación, construir el programa con

gcc -c main.c 
gcc main.o -o <binary name> -ltest 

EDIT:

Realmente no estoy seguro de lo que voy a decir aquí, pero esto podría darle una pista para progresar en su investigación ...

Si no desea usar dlopen y dlsym, se puede tratar de leer la tabla de símbolos del archivo .o con el fin de encontrar la dirección de la función, y luego, mmap el archivo de objeto en la memoria con la lectura y ejecución de los derechos. Entonces debería poder ejecutar el código cargado en la dirección que encontró. Pero tenga cuidado con las otras dependencias que podría encontrar en este código.

Puede comprobar la página hombre elf(5)

+0

Precisamente no quiero usar enlaces dinámicos, edité la pregunta en consecuencia – shodanex

+0

** dlopen ** y ** dlsym ** no implican enlaces dinámicos (ya que su programa no estará vinculado a la biblioteca, su binario ganó no depende de ello, y la biblioteca no será necesaria durante la compilación). La función ** dlopen ** le permite cargar una biblioteca, y ** dlsym ** devolverá la dirección de la función, según el nombre del símbolo que proporcionó. – phsym

+0

dlsym significa llamar al enlazador dinámico proporcionado por OS para analizar el archivo de la biblioteca, realizar un mapeo, etc. ... – shodanex

6

En primer lugar, como otro dijo que usted debe considerar el uso de una DLL o SO.

Dicho esto, si realmente desea hacer esto, debe reemplazar el script del enlazador. Algo como esto (no muy bien probado, pero creo que funciona):

ENTRY(_dummy_start) 
SECTIONS 
{ 
    _dummy_start = 0; 
    _GLOBAL_OFFSET_TABLE_ = 0; 
    .all : { 
     _all = .; 
     LONG(f1 - _all); 
     *(.text .text.* .data .data.* .rodata .rodata.*) 
    } 
} 

A continuación, compile con:

$ gcc -c -fPIC test.c 

Enlace con:

$ ld -T script.ld test.o -o test.elf 

y extraer el blob binario con :

$ objcopy -j .all -O binary test.elf test.bin 

Probablemente som La explicación de la secuencia de comandos es bienvenida:

  • ENTRY(_dummy_start) Eso solo evita la advertencia de que el programa no tiene un punto de entrada.
  • _dummy_start = 0; Define el símbolo utilizado en la línea anterior. El valor no se usa.
  • _GLOBAL_OFFSET_TABLE_ = 0; Eso evita otro error del enlazador. No creo que realmente necesite este símbolo, por lo que se puede definir como 0.
  • .all Ese es el nombre de la sección que recogerá todos los bytes de su blob. En esta muestra, serán todas las secciones .text, .data y .rodata juntas. Es posible que necesite un poco más si tiene funciones complicadas, en este caso objdump -x test.o es su amigo.
  • LONG(f1 - _all) No es realmente necesario, pero desea saber el desplazamiento de su función en la burbuja, ¿no? No puede suponer que estará en el desplazamiento 0. Con esta línea, los primeros 4 bytes en el blob serán el desplazamiento del símbolo f1 (su función). Cambie LONG con QUAD si usa punteros de 64 bits.

ACTUALIZACIÓN: Y ahora una prueba quick'n'dirty (funciona!):

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/mman.h> 

typedef void (*f1_t)(char *a, char *b, int len); 
f1_t f1; 

int main() 
{ 
    char *blob = (char*)valloc(4096); 
    FILE *f = fopen("test.bin", "rb"); 
    fread(blob, 1, 4096, f); 
    fclose(f); 

    unsigned offs = *(unsigned*)blob; 
    f1 = (f1_t)(blob + offs); 
    mprotect(blob, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); 
    char txt[] = "¡hello world!"; 
    char txt2[sizeof(txt)] = ""; 
    f1(txt, txt2, sizeof(txt) - 1); 
    printf("%s\n%s\n", txt, txt2); 
    return 0; 

} 
+0

'_GLOBAL_OFFSET_TABLE_' probablemente sea necesario si se hace referencia a otros símbolos (como una biblioteca estándar) son hechos. – AProgrammer

+0

@AProgrammer: Pero el OP dice específicamente _no external dependency_, por lo que probablemente no sea necesario.Si accede a cualquier biblioteca, tendrá que vincular estáticamente todas las bibliotecas del blob o hacer la vinculación dinámica a sí mismo ... y eso sería ... complicado. – rodrigo