Necesito optimizar el tamaño de mi ejecutable severamente ( ARM
desarrollo) y noté que en mi esquema de compilación actual ( gcc
+ ld
) los símbolos no utilizados no se eliminan.
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 pueda) .
¿Cuál sería la forma (si existe) de modificar la tubería de mi edificio, de modo que los símbolos no utilizados se eliminen del archivo resultante?
Ni siquiera pensaría en esto, pero mi entorno embebido actual no es muy "poderoso" y ahorrar incluso 500K
los 2M
resultados en un aumento de rendimiento de carga muy bueno.
Actualizar:
Por desgracia, la actual gcc
utilización versión que no tiene la -dead-strip
opción y el -ffunction-sections... + --gc-sections
de ld
no dar ninguna diferencia significativa para los productos resultantes.
Me sorprende que esto incluso se convierta 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?).
boost
bibliotecas, el.exe
archivo resultante contiene muchos archivos de objetos no utilizados y debido a las especificaciones de mi tiempo de ejecución incrustado actual , iniciar una10mb
aplicación lleva mucho más tiempo que, por ejemplo, iniciar una500k
aplicación.Respuestas:
Para GCC, 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:
Vincule las unidades de traducción juntas usando la marca de optimización del vinculador (esto hace que el vinculador descarte las secciones sin referencia):
Entonces, si tiene un archivo llamado test.cpp que tiene dos funciones declaradas en él, pero una de ellas no está en uso, puede omitir la que no se usa con el siguiente comando para gcc (g ++):
(Tenga en cuenta que -Os es una marca de compilador adicional que le dice a GCC que optimice el tamaño)
fuente
mingw
esto no funciona al vincular estáticamente estáticamente libstdc ++ y libgcc con la bandera-static
. La opción del vinculador-strip-all
ayuda bastante, pero aún así el ejecutable generado (o dll) es aproximadamente 4 veces más grande de lo que generaría Visual Studio. El punto es que no tengo control sobre cómolibstdc++
se compiló. Debería haber unald
única opción.Si hay que creer en este hilo , debe proporcionar
-ffunction-sections
y-fdata-sections
a gcc, que colocará cada función y objeto de datos en su propia sección. Luego le da y--gc-sections
a GNU ld para eliminar las secciones no utilizadas.fuente
Querrá verificar sus documentos para su versión de gcc & ld:
Sin embargo, para mí (OS X gcc 4.0.1) encuentro estos para ld
Y esta útil opción
También hay una nota en el gcc / g ++ man de 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.
fuente
mingw
.-dead_strip
no es unagcc
opción.Los hábitos de programación también podrían ayudar; por ejemplo, agregar
static
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); utilizarconst char x[]
siempre que sea posible; ... este documento , aunque habla de objetos dinámicos compartidos, puede contener sugerencias que, si se siguen, pueden ayudar a reducir el tamaño de salida binaria final (si su objetivo es ELF).fuente
.so
en Linux), por lo que los nombres de los símbolos deben conservarse para que las API como elctypes
módulo FFI de Python puedan usarlos para buscar símbolos por nombre en tiempo de ejecución.La respuesta es
-flto
. Tienes que pasarlo a los pasos de compilación y enlace, de lo contrario no hace nada.De hecho, funciona muy bien: ¡redujo 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 que se deba al sistema de compilación que estoy usando (QBS; es muy nuevo), pero en cualquier caso, te recomiendo que solo lo habilites para tu compilación final si es posible, y que pruebes esa compilación a fondo.
fuente
-flto
, no entiendo lo que hace detrás de escena.-flto
él no compila cada archivo en ensamblador, los compila en LLVM IR, y luego el enlace final los compila como si estuvieran todos en una unidad de compilación. Eso significa que puede eliminar las funciones no utilizadas y las que nostatic
son en línea , y probablemente también otras cosas. Ver llvm.org/docs/LinkTimeOptimization.htmlSi bien no se trata estrictamente de símbolos, si se busca tamaño, siempre compile con
-Os
y-s
flags.-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
a veces puede ahorrarle incluso docenas de bytes.fuente
-ffast-math
causado estragos en el código C ++ completamente compatible con los estándares, por lo que nunca lo recomendaría.Me parece que la respuesta que da Nemo es la correcta. Si esas instrucciones no funcionan, el problema puede estar relacionado con la versión de gcc / ld que estás usando. Como ejercicio, compilé un programa de ejemplo usando las instrucciones detalladas aquí.
Luego compilé el código usando interruptores de eliminación de código muerto progresivamente más agresivos:
Estos parámetros de compilación y vinculación 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
fuente
strip --strip-unneeded
solo opera 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 busca al dividir todas sus funciones en archivos de objetos separados, que se combinan usando
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 de objeto y, por lo tanto, los símbolos que se utilizan realmente.También puede encontrar algunas de las respuestas a esta pregunta de uso similar .
fuente
No sé si esto ayudará con su situación actual, ya que se trata de una característica reciente, pero puede especificar la visibilidad de los símbolos de manera global. Pasar la
-fvisibility=hidden -fvisibility-inlines-hidden
compilación puede ayudar al enlazador a deshacerse más tarde de 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 .
fuente
Del manual GCC 4.2.1, sección
-fwhole-program
:fuente
-flto
.Puede utilizar eliminar binarios en un archivo objeto (por ejemplo, ejecutable) para eliminar todos los símbolos de él.
Nota: cambia el archivo en sí y no crea una copia.
fuente