2012-01-22 10 views
14

Ok, esto es solo un ejercicio un poco divertido, pero no puede ser muy difícil compilar programas para algunos sistemas linux antiguos, ¿o sí?cómo portar aplicaciones c/C++ a versiones heredadas del núcleo de Linux

Tengo acceso a un par de sistemas antiguos que ejecutan Linux y tal vez sería interesante ver cómo funcionan bajo carga. Digamos, por ejemplo, que queremos hacer un poco de álgebra lineal usando Eigen, que es una buena biblioteca de solo encabezado. ¿Alguna posibilidad de compilarlo en el sistema de destino?

[email protected]:~ $ uname -a 
Linux local 2.2.16 #5 Sat Jul 8 20:36:25 MEST 2000 i586 unknown 
[email protected]:~ $ gcc --version 
egcs-2.91.66 

Quizás no ... Así que compilemos en un sistema actual. A continuación están mis intentos, principalmente los fallidos. Cualquier otra idea muy bienvenida.

  1. compilar con -m32 -march=i386

    [email protected]:~ $ ./a.out 
    BUG IN DYNAMIC LINKER ld.so: dynamic-link.h: 53: elf_get_dynamic_info: Assertion `! "bad dynamic tag"' failed! 
    
  2. compilar con -m32 -march=i386 -static: Se ejecuta en todas las versiones bastante recientes del kernel, pero no si son un poco mayores con el mensaje de error conocido

    [email protected]:~ $ ./a.out 
    FATAL: kernel too old 
    Segmentation fault 
    

    Este es un error glibc que tiene una versión mínima del kernel compatible, por ejemplo kernel 2.6.4 en mi sistema:

    $ file a.out 
    a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), 
    statically linked, for GNU/Linux 2.6.4, not stripped 
    
  3. Compilar glibc mismo con soporte para el núcleo más antiguo sea posible. This post lo describe con más detalle pero en esencia es la siguiente

    wget ftp://ftp.gnu.org/gnu/glibc/glibc-2.14.tar.bz2 
    tar -xjf glibc-2.14.tar.bz2 
    cd glibc-2.14 
    mkdir build; cd build 
    ../configure --prefix=/usr/local/glibc_32 \ 
          --enable-kernel=2.0.0 \ 
          --with-cpu=i486 --host=i486-linux-gnu \ 
          CC="gcc -m32 -march=i486" CXX="g++ -m32 -march=i486" 
    make -j 4 
    make intall 
    

    No estoy seguro si los --with-cpu y --host opciones hacen nada, lo más importante es forzar el uso de opciones del compilador -m32 -march=i486 de 32 bits construye (por desgracia -march=i386 fianzas con errores después de un tiempo) y --enable-kernel=2.0.0 para hacer que la biblioteca sea compatible con kernels más antiguos. Incidentially, durante configure me dieron el aviso

    WARNING: minimum kernel version reset to 2.0.10 
    

    que todavía es aceptable, supongo. Para obtener una lista de cosas que cambian con diferentes kernels, vea ./sysdeps/unix/sysv/linux/kernel-features.h.

    Ok, así que vamos enlace en contra de la glibc biblioteca recién compilado, un poco desordenado, pero aquí va:

    $ export LIBC_PATH=/usr/local/glibc_32 
    $ export LIBC_FLAGS=-nostdlib -L${LIBC_PATH} \ 
            ${LIBC_PATH}/crt1.o ${LIBC_PATH}/crti.o \ 
            -lm -lc -lgcc -lgcc_eh -lstdc++ -lc \ 
            ${LIBC_PATH}/crtn.o 
    
    $ g++ -m32 -static prog.o ${LIBC_FLAGS} -o prog 
    

    Ya que estamos haciendo una compilación estática del link order es importante y bien puede requerir un poco de ensayo y error , pero en el fondo sabemos por qué opciones gcc da al enlazador:

    $ g++ -m32 -static -Wl,-v file.o 
    

    Nota, crtbeginT.o y crtend.o también están vinculados contra el que no necesitaba para m y programas, así que los dejé fuera. La salida también incluye una línea como --start-group -lgcc -lgcc_eh -lc --end-group que indica interdependencia entre las bibliotecas, consulte this post. Acabo de mencionar -lc dos veces en la línea de comandos gcc que también resuelve la interdependencia.

    derecho, el trabajo duro ha dado sus frutos y ahora conseguir

    $ file ./prog 
    ./prog: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), 
    statically linked, for GNU/Linux 2.0.10, not stripped 
    

    brillante pensé, ahora probarlo en el viejo sistema:

    [email protected]:~ $ ./prog 
    set_thread_area failed when setting up thread-local storage 
    Segmentation fault 
    

    Esto, de nuevo, es un error de glibc mensaje de ./nptl/sysdeps/i386/tls.h. No entiendo los detalles y me rindo.

  4. Compilar en el nuevo sistema g++ -c -m32 -march=i386 y vincular en el anterior. Wow, eso realmente funciona para C y programas sencillos de C++ (sin usar objetos C++), al menos para los pocos que he probado. Esto no es demasiado sorprendente ya que todo lo que necesito de libc es printf (y tal vez algunas matemáticas) cuya interfaz no ha cambiado, pero la interfaz a libstdc++ es muy diferente ahora.

  5. Configura una caja virtual con un sistema linux antiguo y la versión 2.95 de gcc. A continuación, compile la versión 4.x.x de gcc ... lo siento, pero demasiado perezoso para eso en este momento ...

  6. ???

+0

¿Compilar? ¿Una biblioteca de plantillas solo de encabezado? –

+0

Compile un programa de prueba que use esta biblioteca de plantillas. Este es solo un ejemplo de algún código que no se compilaría en la máquina de destino debido a la versión obsoleta de gcc. – user1059432

+0

Ah, está bien. Lo siento, simplemente incomprendido. –

Respuesta

3

La razón por la que no se puede compilar en el sistema original probablemente no tiene nada que ver con la versión del kernel (que podría, pero 2.2 no es generalmente lo suficientemente mayor para que eso sea un obstáculo para la mayoría de código) . El problema es que la cadena de herramientas es antigua (al menos, el compilador). Sin embargo, nada le impide crear una versión más nueva de G ++ con el egcs que está instalado. También puede encontrar problemas con glibc una vez que haya hecho eso, pero al menos debe llegar tan lejos.

Lo que debe hacer va a ser algo como esto:

  • Build última GCC con egcs
  • Reconstruir última GCC con el gcc que acaba de compilar
  • Build últimas binutils y ld con su nuevo compilador

Ahora usted tiene un compilador moderno bien construido y (la mayor parte de) una cadena de herramientas con la que construir su muestra ap plegamiento. Si la suerte no está de tu lado, es posible que también necesites construir una versión más nueva de glibc, pero este es tu problema, la cadena de herramientas, no el kernel.

8

han encontrado la razón para el mensaje de error:

[email protected] $ ./prog 
set_thread_area failed when setting up thread-local storage 
Segmentation fault 

Es porque glibc hace una llamada al sistema a una función que sólo está disponible desde el kernel 2.4.20. En cierto modo, puede verse como un error de glibc, ya que afirma erróneamente que es compatible con kernel 2.0.10 cuando requiere al menos kernel 2.4.20.

Los detalles:

./glibc-2.14/nptl/sysdeps/i386/tls.h 
[...] 
    /* Install the TLS. */             \ 
    asm volatile (TLS_LOAD_EBX            \ 
        "int $0x80\n\t"           \ 
        TLS_LOAD_EBX            \ 
        : "=a" (_result), "=m" (_segdescr.desc.entry_number)  \ 
        : "0" (__NR_set_thread_area),        \ 
        TLS_EBX_ARG (&_segdescr.desc), "m" (_segdescr.desc)); \ 
[...] 
    _result == 0 ? NULL              \ 
    : "set_thread_area failed when setting up thread-local storage\n"; }) 
[...] 

Lo principal aquí es, que llama a la función de montaje int 0x80 que es una llamada al sistema para el núcleo de Linux que decide qué hacer basado en el valor de eax, que se establece a __NR_set_thread_area en este caso y se define en

$ grep __NR_set_thread_area /usr/src/linux-2.4.20/include/asm-i386/unistd.h 
#define __NR_set_thread_area 243 
pero no

en las versiones anteriores del kernel.

Por lo tanto, la buena noticia es que el punto "3. Compilación de glibc con --enable-kernel=2.0.0" probablemente produzca ejecutables que se ejecuten en todos los kernels de Linux> = 2.4.20.

La única posibilidad de que esto funcione con núcleos más antiguos sería desactivar tls (almacenamiento local de subprocesos) pero que no es posible con glibc 2.14, a pesar de que se ofrece como una opción configure.

Cuestiones relacionadas