xcode - programacion - librerias estaticas y dinamicas c++
Símbolo oculto en bibliotecas estáticas compiladas con Xcode/gcc (3)
El truco principal en la ocultación de símbolos dentro de las bibliotecas estáticas es generar un archivo de objeto reubicable (a diferencia de un archivo de biblioteca estática que simplemente consiste en una colección de archivos .o individuales). Para crear un archivo de objeto reubicable, debe elegir su destino en XCode como paquete (a diferencia de "Biblioteca estática Cocoa Touch"). El objetivo Bundle aparece debajo de las plantillas OS X, y puede establecer su destino en iOS en la configuración de compilación si está compilando para iOS.
Una vez que haya configurado su objetivo correctamente, los siguientes pasos ayudarán a que el símbolo se oculte correctamente:
Establezca la opción "Símbolos ocultos por defecto" en Sí en la configuración de compilación. Esto asegura que todos los símbolos compilados en los archivos estén marcados como privados.
Como se trata de una biblioteca, debe mantener algunos símbolos públicos. Debe poner código para las funciones que desea mantener visibles públicamente en archivos separados, y compilar esos archivos con la bandera
-fvisibility=default
(puede establecer este indicador para archivos individuales "Build Phases> Compile Sources> - Compiler Flags" en Xcode). Alternativamente, puede prefijar el nombre de la función / clase que desea que sea visible con la__attribute__((visibility("default")))
.En la configuración de vinculación en el proyecto de código X, configure el tipo Mach-O en "Archivo de objetos reubicables". Lo que esto significa es que todos los archivos .o se volverán a vincular para generar un solo archivo de objeto. Este es el paso que ayuda a marcar todos los símbolos como privados cuando los archivos .o están vinculados en un solo archivo. Si construye una biblioteca estática (es decir, un archivo
.a
), este paso de vinculación no se realiza para que los símbolos nunca se oculten. Por lo tanto, elegir un archivo objeto reubicable como su objetivo es fundamental.Incluso después de marcar los símbolos como privados, aún aparecen en el archivo .o. Debe habilitar la extracción para deshacerse de los símbolos privados. Esto puede hacerse configurando la configuración "Producto vinculado eliminado" en Sí en la configuración de compilación. Al establecer esta opción, se ejecuta el comando
strip -x
en el archivo del objeto que elimina los símbolos privados del archivo del objeto.Verifique dos veces que todos los símbolos internos hayan desaparecido ejecutando el comando nm en el último archivo de objeto reubicable generado por el proceso de compilación.
Los pasos anteriores le ayudarán a deshacerse de los nombres de símbolos del comando nm. Todavía verá algunos nombres de funciones y archivos si ejecuta el comando strings en su archivo de objeto (debido a algunas cadenas y nombres de objetos compilados en excepciones). Uno de mis colleagues tiene un script que cambia el nombre de algunos de estos símbolos mirando en las secciones binarias y renombrando esas cadenas. Lo publiqué aquí para que lo use: https://gist.github.com/varungulshan/6198167 . Puede agregar esta secuencia de comandos como un paso de construcción adicional en Xcode.
Estoy tratando de averiguar si puedo construir una biblioteca estática que oculte todos sus objetos y funciones internas, etc., excepto las interfaces que deseo exportar. Estoy experimentando con Xcode (gcc 4.2).
He utilizado el __attribute__((visibility("hidden")))
en algunas clases de C ++ según esta documentación . También definí las pequeñas funciones del helper C como file-local (estático), etc.
Sin embargo, cuando ejecuto strings
en el archivo de biblioteca .a resultante, incluso cuando se compila en la configuración de Release, aún veo los nombres de mis clases aparentemente ocultas, con sus nombres de métodos e incluso los nombres de las funciones de archivos locales desparramadas en ahí también.
He agregado la -fvisibility=hidden
e incluso -fno-rtti
a las banderas de gcc. Si bien esto reduce algunas de las cadenas, los nombres de las clases, los nombres de los métodos y los nombres de las funciones estáticas siguen estando ahí en forma simple o mutilada, pero legible.
¿Hay alguna manera confiable de hacer que el compilador construya esto sin tener los nombres de las cadenas de todos los elementos internos emitidos en el binario? No debería ser necesario para cualquier cliente externo que se vincule.
(Para aclarar: estoy preguntando sobre la ofuscación de nombres internos, frente a las necesidades de enlace de exportación literales. Estoy desconcertado de que todo el funcionamiento interno sea visible a través del comando strings
, independientemente de si estos símbolos se exportan formalmente o no).
Gracias.
No tengo muy claro cómo ocultar los símbolos en las bibliotecas estáticas del entorno de línea de comandos de Linux en función de las respuestas anteriores, así que solo publicaré mi solución aquí para la posteridad (dado que este es uno de los principales resultados en Google para ese pregunta).
Digamos que tienes estos dos archivos .c:
// f1.c
const char *get_english_greeting(void)
{
return "hello";
}
__attribute__((visibility("default")))
const char *get_greeting(void)
{
return get_english_greeting();
}
y
// f2.c
#include <stdio.h>
const char *get_english_greeting(void);
__attribute__((visibility("default")))
void print_greeting(void)
{
puts(get_english_greeting());
}
Desea convertir estos dos archivos en una biblioteca estática exportando tanto get_greeting
como print_greeting
pero no get_english_greeting
que no desea que sea estático ya que le gustaría usarlo en toda su biblioteca.
Estos son los pasos para lograr eso:
gcc -fvisibility=hidden -c f1.c f2.c
ld -r f1.o f2.o -o libf.o
objcopy --localize-hidden libf.o
ar rcs libf.a libf.o
Ahora esto funciona:
// gcc -L. main.c -lf
void get_greeting(void);
void print_greeting(void);
int main(void)
{
get_greeting();
print_greeting();
return 0;
}
Y esto no:
// gcc -L. main.c -lf
const char *get_english_greeting(void);
int main(void)
{
get_english_greeting();
return 0;
}
Para este último, obtienes este error:
/tmp/ccmfg54F.o: In function `main'':
main.c:(.text+0x8): undefined reference to `get_english_greeting''
collect2: error: ld returned 1 exit status
Que es lo que queremos
Tenga en cuenta que los nombres de símbolos ocultos aún son visibles en la biblioteca estática, pero el vinculador se negará a vincularlos fuera de dicha biblioteca estática. Para eliminar por completo los nombres de los símbolos, deberá quitarlos y ofuscarlos.
Ocultar nombres internos requiere algunas configuraciones simples de compilación de Xcode, y generalmente no es necesario modificar la fuente o cambiar el tipo de producto creado.
- Elimine cualquier símbolo interno requerido entre los módulos mediante la realización de un enlace previo de un solo objeto. Establezca la configuración de compilación de Xcode llamada "Realizar prelink de un solo objeto" en Sí (GENERATE_MASTER_OBJECT_FILE = YES). Esto hace que ld se ejecute con el indicador "-r".
- Asegúrese de que la configuración "Estilo de banda" esté configurada como "Símbolos no globales" (STRIP_STYLE = no global), esto pasa "-x" a ld.
- La eliminación solo se realiza realmente en bibliotecas estáticas si el procesamiento posterior está habilitado (y este no es el valor predeterminado). Establezca la configuración de compilación de Xcode "Deptoyment Postprocessing" en yes. (DEPLOYMENT_POSTPROCESSING = YES). También asegúrese de que "Usar tira separada" esté configurado a Sí (no siempre el predeterminado) (SEPARATE_STRIP = YES).
- Si, además de los símbolos locales, si necesita eliminar algunos de los símbolos globales, puede proporcionar opciones adicionales al comando strip, bajo la configuración de creación de Xcode "Banderas de bandas adicionales". Por ejemplo, comúnmente utilizo la opción strip "-R somefile" para proporcionar un archivo con una lista adicional de símbolos que deseo eliminar de la tabla de símbolos global.