Pregunta

Estoy generando un archivo hex para ejecutarlo en un procesador ARM que quiero mantener por debajo de 32K. Actualmente es mucho más grande que eso y me pregunté si alguien podría tener algún consejo sobre cuál es el mejor enfoque para adelgazar.

Esto es lo que he hecho hasta ahora

  1. Así que he ejecutado 'tamaño' en él para determinar qué tan grande es el archivo hexadecimal.
  2. Luego 'tamaño' nuevamente para ver qué tan grande es cada enlace de los archivos de objeto para crear los archivos hexadecimales. Parece que la mayoría del tamaño proviene de bibliotecas externas.
  3. Luego usé 'readelf' para ver qué funciones ocupan más memoria.
  4. Busqué en el código para ver si podía eliminar las llamadas a esas funciones.

Aquí es donde me quedo atascado, hay algunas funciones que no llamo directamente (por ejemplo, _vfprintf) y no puedo encontrar lo que lo llama, así que puedo eliminar la llamada (ya que creo que no la necesito).

¿Cuáles son los próximos pasos?

Respuesta a las respuestas:

  • Como puedo ver, hay funciones llamadas que ocupan mucha memoria. Sin embargo, no puedo encontrar lo que lo está llamando.
  • ¡Quiero omitir esas funciones (si es posible) pero no puedo encontrar lo que las está llamando! Podría llamarse desde cualquier número de funciones de la biblioteca, supongo.
  • El enlazador está funcionando como se desea, creo que solo incluye los archivos de biblioteca relevantes. ¿Cómo sabes si solo se están incluyendo las funciones relevantes? ¿Puedes establecer una bandera o algo para eso?
  • Estoy usando GCC
¿Fue útil?

Solución

Lista general:

  • Asegúrese de tener desactivadas las opciones de depuración del compilador y del vinculador
  • Compilar y vincular con todas las opciones de tamaño activadas (-Os en gcc)
  • Ejecutar strip en el ejecutable
  • Genere un archivo de mapa y verifique los tamaños de sus funciones. Puede hacer que su enlazador genere su archivo de mapa ( -M al usar ld), o puede usar objdump en el ejecutable final (tenga en cuenta que esto solo funcionará en un ejecutable sin rayas). En realidad no solucionamos el problema, pero le informará sobre los peores delincuentes.
  • Use nm para investigar los símbolos que se llaman desde cada uno de sus archivos de objeto. Esto debería ayudar a encontrar quién llama a las funciones que no quiere que se llamen.

En la pregunta original había una subpregunta sobre la inclusión de solo funciones relevantes. gcc incluirá todas las funciones dentro de cada archivo de objeto que se use. Para decirlo de otra manera, si tiene un archivo de objeto que contiene 10 funciones, las 10 funciones se incluyen en su ejecutable, incluso si se llama realmente a 1.

Las bibliotecas estándar (por ejemplo, libc) dividirán las funciones en muchos archivos de objetos separados, que luego se archivan. El ejecutable se vincula contra el archivo. Al dividirse en muchos archivos de objetos, el enlazador puede incluir solo las funciones que realmente se llaman. (esto supone que estás enlazando estáticamente)

No hay ninguna razón por la que no puedas hacer el mismo truco. Por supuesto, podría argumentar que si las funciones no se llaman, probablemente las pueda eliminar usted mismo.

Si está enlazando estáticamente con otras bibliotecas, también puede ejecutar las herramientas enumeradas anteriormente sobre ellas para asegurarse de que sigan reglas similares.

Otros consejos

Otra optimización que podría ahorrarle trabajo es las secciones -ffunction, -Wl, -gc, asumiendo que está usando GCC. Sin embargo, una buena cadena de herramientas no necesitará que se le diga eso.

Explicación: las secciones de enlaces de ln de GNU y GCC emiten una sección por unidad de traducción, a menos que usted le indique lo contrario. Pero en C ++, los nodos en el gráfico de dependencia son objetos y funciones.

Solo para verificar y documentar para futuras referencias, ¿pero usa las instrucciones de Thumb? Son versiones de 16 bits de las instrucciones normales. A veces es posible que necesite 2 instrucciones de 16 bits, por lo que no ahorrará el 50% en el espacio de código.

Un enlazador decente debería tomar solo las funciones necesarias. Sin embargo, es posible que necesites compilador & amp; Configuración de enlaces a funciones de paquetes para enlaces individuales.

En proyectos profundamente integrados, siempre trato de evitar el uso de funciones de biblioteca estándar. Incluso funciones simples como " strtol () " volar el tamaño binario. Si es posible, simplemente evita esas llamadas.

En la mayoría de los proyectos integrados, no necesita un " printf () " versátil o asignación de memoria dinámica (muchos controladores tienen 32kb o menos RAM).

En lugar de simplemente usar " printf () " Yo uso un personalizado muy simple " printf () " ;, esta función solo puede imprimir números en formato hexadecimal o decimal, no más. La mayoría de las estructuras de datos se preasignan en el momento de la compilación.

Ok, al final, simplemente reduje el proyecto a su forma más simple, luego agregué los archivos lentamente uno por uno hasta que la función que quería eliminar apareciera en el archivo 'readelf'. Luego, cuando tuve el archivo, comenté todo y lentamente volví a agregar cosas hasta que la función volvió a aparecer. Así que al final descubrí cómo se llamaba y eliminé todas esas llamadas ... Ahora funciona como se desea ... ¡dulce!

Aunque debe ser una mejor manera de hacerlo.

Andrew EdgeCombe tiene una gran lista, pero si realmente desea raspar hasta el último byte, sstrip es una buena herramienta que falta en la lista y puede eliminar algunos kB más.

Por ejemplo, cuando se ejecuta en strip , se puede afeitar ~ 2kB .

De un antiguo README (vea los comentarios en la parte superior de este archivo fuente indirecto):

  

sstrip es una pequeña utilidad que elimina los contenidos al final de un   Archivo ELF que no forma parte de la imagen de memoria del programa.

     

La mayoría de los archivos ejecutables de ELF se crean con una tabla de encabezado de programa y una   tabla de encabezado de sección. Sin embargo, solo se requiere lo primero para   para que el SO cargue, enlace y ejecute un programa. sstrip intenta   extraiga el encabezado ELF, la tabla del encabezado del programa y su contenido,   dejando todo lo demás en el cubo de bits. Solo puede quitar partes de   el archivo que aparece al final, después de las partes que se guardarán. Sin embargo,   esto casi siempre incluye la tabla de encabezado de sección, y ocasionalmente   algunas secciones aleatorias que no se utilizan al ejecutar un programa.

Tenga en cuenta que debido a parte de la información que elimina, un ejecutable sstrip'd es se rumorea que tiene problemas con algunas herramientas. Esto se discute más en los comentarios de la fuente.

También ... para una lectura entretenida / loca sobre cómo hacer el ejecutable más pequeño posible, este artículo vale la pena leerlo.

Para responder a esta necesidad específica:

  

& # 8226; Quiero omitir esas funciones (si es posible) pero no puedo encontrar qué   llamandolos !! Podría llamarse desde cualquier número de funciones de biblioteca I   adivinar.

Si desea analizar su base de código para ver quién llama a qué, quién llama a una función determinada y cosas por el estilo, hay una gran herramienta llamada " Understand C " proporcionado por SciTools.

https://scitools.com/

Lo he usado muy a menudo en el pasado para realizar análisis de código estático. Realmente puede ayudar a determinar el árbol de dependencia de la biblioteca. Permite navegar fácilmente hacia arriba y hacia abajo en el árbol de llamadas, entre otras cosas.

Proporcionan una evaluación de tiempo limitado, luego debes comprar una licencia.

Puede ver algo como compresión ejecutable .

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