Pregunta

Estamos utilizando un compilador heredado, basado en GCC 2.6.0, para compilar cruzados para un antiguo procesador incrustado que todavía estamos usando (sí, ¡todavía está en uso desde 1994!). El ingeniero que realizó el puerto GCC para este chip ha avanzado desde hace mucho tiempo. Aunque podríamos recuperar la fuente GCC 2.6.0 de algún lugar de la web, el cambio establecido para este chip ha desaparecido en los pasillos de la historia corporativa. Nos hemos confundido hasta hace poco, ya que el compilador todavía corría y produjo ejecutables viables, pero a partir del kernel de Linux 2.6.25 (y también 2.6.26) falla con el mensaje gcc: virtual memory exhausted... incluso cuando se ejecuta sin parámetros o solo con -v. He reiniciado mi sistema de desarrollo (de 2.6.26) usando el núcleo 2.6.24 y el compilador funciona nuevamente (reiniciar con 2.6.25 no).

Tenemos un sistema que mantenemos en 2.6.24 solo con el propósito de hacer compilaciones para este chip, pero nos sentimos un poco expuestos en caso de que el mundo de Linux pase al punto de que ya no podemos reconstruir un sistema que se ejecute El compilador (es decir, nuestro sistema 2.6.24 muere y no podemos obtener 2.6.24 para instalar y ejecutar en un nuevo sistema porque algunas de las piezas de software ya no están disponibles).

¿Alguien tiene alguna idea de lo que podríamos hacer a una instalación más moderna para que este compilador heredado se ejecute?

Editar:

Para responder algunos de los comentarios ...

Lamentablemente, son los cambios del código fuente los que son específicos de nuestro chip que se pierden. Esta pérdida ocurrió en dos principales reorgs de la compañía y varios sistemas (un par de los cuales realmente dejaron un desastre). Ahora usamos el control de configuración, pero eso está cerrando la puerta del granero demasiado tarde para este problema.

El uso de una VM es una buena idea, y puede ser lo que terminamos haciendo. Gracias por esa idea.

Finalmente, probé Strace como sugirió Efemient y descubrí que la última llamada del sistema fue BRK () que devolvió un error en el nuevo sistema (2.6.26 kernel) y devolvió el éxito en el sistema anterior (núcleo 2.6.24). Esto indicaría que realmente me estoy quedando sin memoria virtual, excepto que el "límite" de TCSH devuelve los mismos valores en sistemas antiguos y nuevos, y /Proc /MemInfo muestra que los nuevos sistemas tienen un poco más de memoria y un poco más de espacio de intercambio. ¿Quizás es un problema de fragmentación o dónde se está cargando el programa?

Sin embargo, hice más investigaciones y la "aleatorización de brk" en el núcleo 2.6.25, sin embargo, CONFIG_COMPAT_BRK Supuestamente está habilitado por defecto (que deshabilita la aleatorización de BRK).

Editar:

Ok, más información: realmente parece que la aleatorización de BRK es el culpable, el Legacy GCC está llamando a BRK () para cambiar el final del segmento de datos y que ahora falla, lo que hace que el GCC heredado informe "Memoria virtual agotada". Hay algunas formas documentadas de deshabilitar la aleatorización de BRK:

  • sudo echo 0 > /proc/sys/kernel/randomize_va_space

  • sudo sysctl -w kernel.randomize_va_space=0

  • Comenzando un nuevo caparazón con setarch i386 -R tcsh (o "-r -l")

Los he probado y parecen tener un efecto en el sentido de que el valor de retorno BRK () es diferente (y siempre el mismo) que sin ellos (probado en el núcleo 2.6.25 y 2.6.26), pero el brk () Todavía falla, por lo que el Legacy GCC todavía falla :-(.

Además, he establecido vm.legacy_va_layout=1 y vm.overcommit_memory=2 sin cambios, y he reiniciado con el vm.legacy_va_layout=1 y kernel.randomize_va_space=0 Configuración guardada en /etc/sysctl.conf. Todavía no hay cambios.

Editar:

Usando kernel.randomize_va_space=0 en el kernel 2.6.26 (y 2.6.25) da como resultado la siguiente llamada brk () que se informa por strace legacy-gcc:

brk(0x80556d4) = 0x8056000

Esto indica que BRK () falló, pero parece que falló porque el segmento de datos ya termina más allá de lo que se solicitó. Usando Objdump, puedo ver que el segmento de datos debe finalizar a 0x805518c, mientras que el fallido brk () indica que el segmento de datos actualmente termina a 0x8056000:

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .interp       00000013  080480d4  080480d4  000000d4  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .hash         000001a0  080480e8  080480e8  000000e8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .dynsym       00000410  08048288  08048288  00000288  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .dynstr       0000020e  08048698  08048698  00000698  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .rel.bss      00000038  080488a8  080488a8  000008a8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .rel.plt      00000158  080488e0  080488e0  000008e0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .init         00000008  08048a40  08048a40  00000a40  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  7 .plt          000002c0  08048a48  08048a48  00000a48  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  8 .text         000086cc  08048d10  08048d10  00000d10  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  9 .fini         00000008  080513e0  080513e0  000093e0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 10 .rodata       000027d0  080513e8  080513e8  000093e8  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 11 .data         000005d4  08054bb8  08054bb8  0000bbb8  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 12 .ctors        00000008  0805518c  0805518c  0000c18c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 13 .dtors        00000008  08055194  08055194  0000c194  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 14 .got          000000b8  0805519c  0805519c  0000c19c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 15 .dynamic      00000088  08055254  08055254  0000c254  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 16 .bss          000003b8  080552dc  080552dc  0000c2dc  2**3
                  ALLOC
 17 .note         00000064  00000000  00000000  0000c2dc  2**0
                  CONTENTS, READONLY
 18 .comment      00000062  00000000  00000000  0000c340  2**0
                  CONTENTS, READONLY
SYMBOL TABLE:
no symbols

Editar:

Para hacer eco del comentario de Ephemient a continuación: "¡Tan extraño para tratar el GCC como un binario sin fuente"!

Entonces, usando Strace, Objdump, GDB y mi comprensión limitada del ensamblador y arquitectura 386, he rastreado el problema hasta la primera llamada Malloc en el código heredado. El Legacy GCC llama a MALLOC, que devuelve NULL, que da como resultado el mensaje "Memoria virtual agotada" en Stderr. Este malloc está en libc.so.5, y llama a Getenv un montón de veces y termina llamando a Brk () ... supongo que para aumentar el montón ... que falla.

A partir de esto, solo puedo suponer que el problema es más que la aleatorización de BRK, o no he desactivado completamente la aleatorización de BRK, a pesar de la configuración Randomize_VA_space = 0 y Legacy_VA_Layout = 1 SYSCTL.

¿Fue útil?

Solución

Instale Linux + el GCC antiguo en una máquina virtual.

Otros consejos

Tienes el fuentes para este compilador personalizado? Si puede recuperar la línea de base 2.6.0 (y eso debería ser relativamente fácil), entonces la diff y el parche deben recuperar su conjunto de cambios.

Lo que recomendaría es usar ese cambio establecido para construir una nueva versión contra GCC actualizado. Y luego póngalo bajo el control de configuración.

Lo siento, no quiero gritar. Es solo que he estado diciendo lo mismo durante la mayoría de los 30 años.

Puede strace la gcc-2.6.0 ¿ejecutable? Puede estar haciendo algo como leer /proc/$$/maps, y confundirse cuando la salida cambia de formas insignificantes. Un problema similar fue Recientemente notado entre 2.6.28 y 2.6.29.

Si es así, puedes hackear /usr/src/linux/fs/proc/task_mmu.c o por ahí para restaurar la salida anterior, o configurar algunos $LD_PRELOAD falsificar gcc en leer otro archivo.

Editar

Desde que mencionaste brk...

CONFIG_COMPAT_BRK Hace el valor predeterminado kernel.randomize_va_space=1 en vez de 2, pero eso todavía aleatoriza todo lo que no sea el montón (brk).

Mira si tu problema desaparece si echo 0 > /proc/sys/kernel/randomize_va_space o sysctl kernel.randomize_va_space=0 (equivalente).

Si es así, agregue kernel.randomize_va_space = 0 a /etc/sysctl.conf o agregar norandmaps a la línea de comando del núcleo (equivalente), y sé feliz nuevamente.

Me encontré con este y pensé en tu problema. ¿Puedes encontrar una manera de jugar con el binario para moverlo al formato elfo? O puede ser irrelevante, pero jugar con Objdump puede proporcionarle más información.

¿Puedes echar un vistazo al mapa de memoria del proceso?

Así que he resuelto algo ... no es una solución completa, pero supera el problema original que tuve con el Legacy GCC.

Poner puntos de interrupción en cada llamada LIBC en la .plt (tabla de enlace de procedimiento) Veo que Malloc (en libc.so.5) llama a getenv () para obtener:

    MALLOC_TRIM_THRESHOLD_
    MALLOC_TOP_PAD_
    MALLOC_MMAP_THRESHOLD_
    MALLOC_MMAP_MAX_
    MALLOC_CHECK_

Así que los busqué en web y encontré este que aconsejó

    setenv MALLOC_TOP_PAD_ 536870912

¡Entonces el Legacy GCC funciona!

Pero no en el hogar libre, llegó al enlace en la construcción antes de fallar, por lo que está sucediendo algo más con el legado que tenemos :-( está informando:

    Virtual memory exceeded in `new'

En /etc/sysctl.conf tengo:

    kernel.randomize_va_space=0
    vm.legacy_va_layout=1

Todavía funciona igual si

    kernel.randomize_va_space=1
    vm.legacy_va_layout=0

Pero no si

kernel.randomize_va_space=2

Hubo una sugerencia para usar "LDD" para ver las dependencias de la biblioteca compartida: el Legacy GCC solo necesita libc5, pero el NLD heredado también necesita libg ++. So.27, libstdc ++. So.27, libm.so.5 y aparentemente hay Una versión libc5 de libg ++. So.27 (libg ++ 27-altdev?

Entonces, como dije, aún no está libre de casa ... estar más cerca. Probablemente publicaré una nueva pregunta sobre el problema de NLD.

Editar:

Originalmente iba a abstenerme de "aceptar" esta respuesta, ya que todavía tengo un problema con el enlazador heredado correspondiente, pero para obtener una finalidad en esta pregunta al menos, estoy repensando esa posición.

Gracias a salir a:

  • an0nym0usc0ward para la sugerencia de usar una VM (que en última instancia puede convertirse en la respuesta aceptada)
  • Efemient para sugerir usar Strace y ayudar con el uso de StackoverFlow
  • shodanex por sugerir usar objdump

Editar

A continuación se presentan las últimas cosas que aprendí, y ahora aceptaré la solución VM ya que no pude resolverlo por completo de otra manera (al menos en el tiempo asignado para esto).

Los núcleos más nuevos tienen un indicador de compilación config_compat_brk para permitir que se use libc5, por lo que presumiblemente construir un nuevo núcleo con esta bandera solucionará el problema (y mirando a través del núcleo SRC, parece que lo hará, pero no puedo estar seguro de que lo hice. no seguir todos los caminos). También hay otra forma documentada de permitir el uso de libc5 en tiempo de ejecución (en lugar de en el tiempo de construcción del núcleo): sudo sysctl -w kernel.randomize_va_space = 0. Esto, sin embargo, no hace un trabajo completo y algunas (¿la mayoría?) Las aplicaciones libc5 aún se romperán, por ejemplo, nuestro compilador y enlazador heredado. Esto parece deberse a una diferencia en los supuestos de alineación entre los núcleos más nuevos y mayores. He parcheado el Binario de enlace para que piense que tiene una sección BSS más grande, para llevar el final del BSS a un límite de página, y esto funciona en el núcleo más nuevo cuando el SYSCTL var kernel.randomize_va_space = 0. Esta no es una solución satisfactoria para mí, ya que estoy parcheando ciegamente a un ejecutable binario crítico, y aunque ejecutar el enlazador parcheado en el núcleo más nuevo produjo una salida idéntica de un poco al enlazador original en el núcleo más antiguo, eso no prueba que demuestre que demuestre que demuestre que demuestre que demuestre que Algunas otras entradas de enlazador (es decir, cambiamos el programa que se está vinculando) también producirá resultados idénticos.

¿No podría simplemente hacer una imagen de disco que se pueda reinstalar si el sistema muere? o hacer una VM?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top