¿Cómo eliminar símbolos C/C++ no utilizados con GCC y ld?


Necesito optimizar el tamaño de mi ejecutable severamente (ARM desarrollo) y Me di cuenta de que en mi esquema de construcción actual (gcc + ld) los símbolos no utilizados no son despojados.

El uso de arm-strip --strip-unneeded para los ejecutables / bibliotecas resultantes no cambia el tamaño de salida del ejecutable (no tengo idea de por qué, tal vez simplemente no puede).

¿Cuál sería la forma (si existe) de modificar mi canalización de construcción, de modo que los símbolos no utilizados sean despojado del archivo resultante?


Ni siquiera se me ocurriría esto, pero mi entorno embebido actual no es muy "poderoso" y guardar incluso 500K fuera de 2M resulta en un muy buen aumento del rendimiento de carga.

Actualización:

Desafortunadamente la versión actual gcc que uso no tiene la opción -dead-strip y el -ffunction-sections... + --gc-sections para ld no da ninguna diferencia significativa para la salida resultante.

Estoy sorprendido de que esto incluso se convirtió en un problema, porque estaba seguro de que gcc + ld debería eliminar automáticamente los símbolos no utilizados (¿por qué tienen que conservarlos?).

11 answers

Para el CCG, esto se logra en dos etapas:

Primero compile los datos pero dígale al compilador que separe el código en secciones separadas dentro de la unidad de traducción. Esto se hará para funciones, clases y variables externas mediante el uso de los siguientes dos indicadores del compilador:

-fdata-sections -ffunction-sections

Enlaza las unidades de traducción usando el indicador de optimización del enlazador (esto hace que el enlazador deseche las secciones no referenciadas):

-Wl,--gc-sections

Así que si tuvieras un archivo llamado test.cpp que tenía dos funciones declaradas en él, pero una de ellas no estaba utilizada, podría omitir la no utilizada con el siguiente comando a gcc (g++):

gcc -Os -fdata-sections -ffunction-sections test.cpp -o test -Wl,--gc-sections

(Tenga en cuenta que-Os es un indicador de compilador adicional que le dice a GCC que optimice el tamaño)

 105
Author: J T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-11 10:02:53

Si este hilo se debe creer, es necesario suministrar el -ffunction-sections y -fdata-sections a gcc, que pondrá cada función y objeto de datos en su propia sección. Luego das y --gc-sections a GNU ld para eliminar las secciones no utilizadas.

 31
Author: Nemo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-22 23:35:29

Usted querrá comprobar sus documentos para su versión de gcc & ld:

Sin embargo para mí (OS X gcc 4.0.1) encuentro estos para ld

-dead_strip

Elimine las funciones y los datos que no son accesibles por el punto de entrada o los símbolos exportados.

-dead_strip_dylibs

Elimine los dylibs que son inalcanzables por el punto de entrada o los símbolos exportados. Es decir, suprime la generación de comandos de carga para dylibs que no proporcionaron símbolos durante el enlace. Esta opción no debe utilizarse cuando enlazar contra un dylib que se requiere en tiempo de ejecución por alguna razón indirecta como el dylib tiene un inicializador importante.

Y esta útil opción

-why_live symbol_name

Registra una cadena de referencias a symbol_name. Solo aplicable con -dead_strip. Puede ayudar a depurar por qué algo que crees que debería ser eliminado de la tira muerta no se elimina.

También hay una nota en el man de gcc/g++ que ciertos tipos de eliminación de código muerto solo se realizan si la optimización se habilita al compilar.

Si bien estas opciones/condiciones pueden no ser válidas para su compilador, le sugiero que busque algo similar en sus documentos.

 22
Author: Michael Anderson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-16 03:11:03

Los hábitos de programación también podrían ayudar; por ejemplo, agregar static a funciones a las que no se accede fuera de un archivo específico; usar nombres más cortos para símbolos (puede ayudar un poco, probablemente no demasiado); usar const char x[] cuando sea posible; ... este documento, aunque habla de objetos compartidos dinámicos, puede contener sugerencias que, si se siguen, pueden ayudar a reducir el tamaño de la salida binaria final (si su objetivo es ELF).

 19
Author: ShinTakezou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-16 14:26:51

La respuesta es -flto. Tienes que pasarlo a tus pasos de compilación y enlace, de lo contrario no hace nada.

En realidad funciona muy bien-reducido el tamaño de un programa de microcontrolador que escribí a menos del 50% de su tamaño anterior!

Desafortunadamente parecía un poco con errores - tuve casos de cosas que no se construyeron correctamente. Puede haber sido debido al sistema de compilación que estoy usando (QBS; es muy nuevo), pero en cualquier caso te recomiendo que solo lo habilites para tu final construir si es posible, y probar que construir a fondo.

 14
Author: Timmmm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-18 10:29:48

Aunque no se trata estrictamente de símbolos, si va por tamaño, siempre compile con -Os y -s banderas. -Os optimiza el código resultante para el tamaño mínimo del ejecutable y -s elimina la tabla de símbolos y la información de reubicación del ejecutable.

A veces - si se desea un tamaño pequeño - jugar con diferentes indicadores de optimización puede - o no - tener importancia. Por ejemplo, alternar -ffast-math y/o -fomit-frame-pointer puede a veces ahorrarle incluso docenas de bytes.

 12
Author: zxcdw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-22 12:23:52

Me parece que la respuesta dada por Nemo es la correcta. Si esas instrucciones no funcionan, el problema puede estar relacionado con la versión de gcc/ld que está utilizando, como ejercicio compilé un programa de ejemplo utilizando instrucciones detalladas aquí

#include <stdio.h>
void deadcode() { printf("This is d dead codez\n"); }
int main(void) { printf("This is main\n"); return 0 ; }

Luego compilé el código usando interruptores de eliminación de código muerto progresivamente más agresivos:

gcc -Os test.c -o test.elf
gcc -Os -fdata-sections -ffunction-sections test.c -o test.elf -Wl,--gc-sections
gcc -Os -fdata-sections -ffunction-sections test.c -o test.elf -Wl,--gc-sections -Wl,--strip-all

Estos parámetros de compilación y enlace produjeron ejecutables de tamaño 8457, 8164 y 6160 bytes, respectivamente, la contribución más sustancial proviene de la declaración "strip-all". Si no puede producir reducciones similares en su plataforma,entonces tal vez su versión de gcc no admita esta funcionalidad. Estoy usando gcc(4.5.2-8ubuntu4), ld (2.21.0.20110327) en Linux Mint 2.6.38-8-generic x86_64

 11
Author: Gearoid Murphy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-18 13:44:32

strip --strip-unneeded solo funciona en la tabla de símbolos de su ejecutable. En realidad, no elimina ningún código ejecutable.

Las bibliotecas estándar logran el resultado que buscas dividiendo todas sus funciones en archivos objeto separados, que se combinan usando ar. Si luego enlaza el archivo resultante como una biblioteca (ie. dé la opción -l your_library a ld) entonces ld solo incluirá los archivos objeto, y por lo tanto los símbolos, que se utilizan realmente.

También puede encontrar algunos de los respuestas a esta pregunta similar de uso.

 7
Author: Andrew Edgecombe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:55:03

No se si esto ayudará con su situación actual ya que esta es una característica reciente, pero puede especificar la visibilidad de los símbolos de una manera global. Pasar -fvisibility=hidden -fvisibility-inlines-hidden en la compilación puede ayudar al enlazador a deshacerse más tarde de símbolos innecesarios. Si estás produciendo un ejecutable (a diferencia de una biblioteca compartida) no hay nada más que hacer.

Más información (y un enfoque detallado para, por ejemplo, bibliotecas) está disponible en la wiki de GCC.

 4
Author: Luc Danton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-17 16:01:30

Del manual 4.2.1 del CCG, sección -fwhole-program:

Supongamos que la unidad de compilación actual representa todo el programa que se está compilando. Todas las funciones y variables públicas con la excepción de main y las fusionadas por atributo externally_visible se convierten en funciones estáticas y en un efecto se optimiza más agresivamente por los optimizadores interprocedurales. Si bien esta opción es equivalente al uso adecuado de la palabra clave static para programas que consisten en un solo archivo, en combinación con la opción --combine flag se puede usar para compilar la mayoría de programas C de menor escala ya que las funciones y variables se vuelven locales para toda la unidad de compilación combinada, no para el archivo fuente único en sí.

 4
Author: awiebe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-13 12:50:54

Puede usar el binario de tira en el archivo objeto(por ejemplo. ejecutable) para quitar todos los símbolos de él.

Nota: cambia el archivo por sí mismo y no crea una copia.

 -1
Author: ton4eg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-24 18:43:09