c++ - compiler - gcc linux install
¿Cómo eliminar los símbolos C/C++ no utilizados con GCC y ld? (11)
Necesito optimizar el tamaño de mi ejecutable severamente (desarrollo ARM
) y noté que en mi esquema de compilación actual ( gcc
+ ld
) los símbolos que no se usan no se eliminan.
El uso de la arm-strip --strip-unneeded
para los ejecutables / bibliotecas resultantes no cambia el tamaño de salida del ejecutable (no tengo ni idea de por qué, tal vez simplemente no puede) .
¿Cuál sería el camino (si existe) para modificar mi canalización de construcción, de modo que los símbolos no utilizados se eliminen del archivo resultante?
Ni siquiera pensaría en esto, pero mi entorno integrado actual no es muy "potente" y ahorra incluso 500K
de los resultados de 2M
en un impulso de carga muy agradable.
Actualizar:
Desafortunadamente, la versión actual de gcc
que uso no tiene la opción -dead-strip
y las -ffunction-sections... + --gc-sections
para ld
no da ninguna diferencia significativa para la salida resultante.
Estoy sorprendido de que esto incluso se haya convertido en un problema, porque estaba seguro de que gcc + ld
debería quitar automáticamente los símbolos que no se usan (¿por qué incluso tienen que guardarlos?).
Deberá verificar sus documentos para su versión de gcc & ld:
Sin embargo, para mí (OS X gcc 4.0.1) encuentro esto para ld
-dead_strip
Elimine las funciones y los datos que son inalcanzables por el punto de entrada o los símbolos exportados.
-dead_strip_dylibs
Elimina dylibs que no son alcanzables por el punto de entrada o símbolos exportados. Es decir, suprime la generación de comandos de comando de carga para dylibs que no suministraron símbolos durante el enlace. Esta opción no se debe utilizar cuando se realiza una vinculación con un archivo dylib que se requiere en el tiempo de ejecución por algún motivo indirecto, como que 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é no se elimina algo que crees que debería eliminarse.
También hay una nota en el hombre de gcc / g ++ que dice que ciertos tipos de eliminación de código muerto solo se realizan si la optimización está habilitada al compilar.
Si bien estas opciones / condiciones pueden no ser válidas para su compilador, le sugiero que busque algo similar en sus documentos.
Del manual GCC 4.2.1, sección -fwhole-program
:
Supongamos que la unidad de compilación actual representa el programa completo que se está compilando. Todas las funciones y variables públicas con la excepción de
main
y las fusionadas por atributoexternally_visible
convierten en funciones estáticas y en un efecto se optimiza de forma más agresiva mediante optimizadores interprocedimientos. Si bien esta opción es equivalente al uso adecuado de palabra clavestatic
para programas que constan de un solo archivo, en combinación con la opción--combine
este indicador se puede usar para compilar la mayoría de los programas de C de menor escala ya que las funciones y variables se vuelven locales para toda la compilación combinada unidad, no para el único archivo fuente en sí.
La respuesta es -flto
. Tienes que pasarlo a tus pasos de compilación y enlace, de lo contrario no hace nada.
De hecho, funciona muy bien: ¡reduje el tamaño de un programa de microcontrolador que escribí a menos del 50% de su tamaño anterior!
Desafortunadamente, parecía un poco defectuoso. Tuve casos de cosas que no se construyeron correctamente. Puede deberse al sistema de compilación que estoy usando (QBS, es muy nuevo), pero en cualquier caso, le recomendaría que solo lo habilite para su compilación final, si es posible, y pruebe esa compilación a fondo.
Los hábitos de programación también podrían ayudar; por ejemplo, agregar static
a las funciones a las que no se accede fuera de un archivo específico; use nombres más cortos para los símbolos (puede ayudar un poco, probablemente no demasiado); use const char x[]
donde sea posible; ... este documento , aunque se trata de objetos compartidos dinámicos, puede contener sugerencias que, si se siguen, pueden ayudar a reducir el tamaño final de la salida binaria (si su objetivo es ELF).
Me parece que la respuesta proporcionada 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 usando las instrucciones detalladas here
#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 proveniente 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
No sé 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 forma global. Pasar -fvisibility=hidden -fvisibility-inlines-hidden
en la compilación puede ayudar al enlazador a eliminar más adelante los símbolos innecesarios. Si está 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 .
Para GCC, esto se logra en dos etapas:
Primero compila los datos pero dile 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
Vincule las unidades de traducción utilizando la bandera de optimización del enlazador (esto hace que el enlazador descarte las secciones sin referencia):
-Wl,--gc-sections
Entonces, si tenía un archivo llamado test.cpp que tenía dos funciones declaradas, pero una de ellas no se utilizaba, podía omitir la que no se usa con el siguiente comando para gcc (g ++):
gcc -Os -fdata-sections -ffunction-sections test.cpp -o test -Wl,--gc-sections
(Tenga en cuenta que -Os es un indicador de compilación adicional que le dice a GCC que optimice para el tamaño)
Puede usar strip binary en el archivo de objeto (por ejemplo, ejecutable) para quitar todos los símbolos de él.
Nota: cambia el archivo y no crea copia.
Si bien no se trata estrictamente de símbolos, si se trata de tamaños, compilar siempre con -Os
y -s
flags. -Os
optimiza el código resultante para el tamaño mínimo 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 distintas banderas de optimización puede tener significado o no. Por ejemplo, alternar -ffast-math
y / o -fomit-frame-pointer
a veces puede ahorrar incluso docenas de bytes.
Si se quiere creer en este hilo , debe proporcionar las -ffunction-sections
-fdata-sections
a gcc, que colocarán cada función y objeto de datos en su propia sección. Luego, da y --gc-sections
a GNU ld para eliminar las secciones no utilizadas.
strip --strip-unneeded
solo opera en la tabla de símbolos del ejecutable. En realidad, no elimina ningún código ejecutable.
Las bibliotecas estándar obtienen el resultado que busca al dividir todas sus funciones en archivos de objetos separados, que se combinan utilizando ar
. Si luego vincula el archivo resultante como una biblioteca (es decir, le da la opción -l your_library
a ld) entonces ld solo incluirá los archivos objeto, y por lo tanto los símbolos, que realmente se usan.
También puede encontrar algunas de las respuestas a esta pregunta similar de uso.