c++ c linker glibc static-linking

c++ - ¿Por qué se desalienta estáticamente el enlace glibc?



linker static-linking (3)

La mayoría de las fuentes en línea afirman que puede vincular estáticamente glibc, pero desalientan hacerlo; Por ejemplo, centos paquete repo :

The glibc-static package contains the C library static libraries for -static linking. You don''t need these, unless you link statically, which is highly discouraged.

Estas fuentes rara vez (o nunca) dicen por qué sería una mala idea.


La interfaz programa / glibc está estandarizada y documentada por POSIX, los estándares C y C ++ y otros. Por ejemplo, la función fopen() comporta según el estándar C y pthread_mutex_lock() por POSIX.

La interfaz glibc / kernel no está estandarizada. ¿ fopen() usa open() debajo del capó? ¿O usa openat() ? ¿O algo mas? ¿Qué usará el próximo año? Usted no sabe

Si la interfaz glibc / kernel cambia, un programa que usa lo que haya cambiado pero está enlazado estáticamente glibc ya no funcionará.

Hace más de 15 años, Solaris eliminó todas las versiones estáticas de libc por esta misma razón.

Vinculación estática: ¿a dónde se fue?

Con Solaris 10 ya no puede construir un ejecutable estático. No es que ld (1) no permita la vinculación estática o el uso de archivos, es solo que libc.a, la versión de archivo de libc.so.1, ya no se proporciona. Esta biblioteca proporciona las interfaces entre la tierra del usuario y el núcleo, y sin esta biblioteca es bastante difícil crear cualquier forma de aplicación.

Hemos estado advirtiendo a los usuarios contra el enlace estático desde hace algún tiempo, y el enlace contra libc.a ha sido especialmente problemático. Cada lanzamiento o actualización de Solaris (incluso algunos parches) ha resultado en alguna aplicación que fue construida contra libc.a, fallando. El problema es que se supone que libc aísla una aplicación del límite de usuario / núcleo, un límite que puede sufrir cambios de una versión a otra.

Si una aplicación se compila contra libc.a, cualquier interfaz de kernel a la que haga referencia se extrae del archivo y se convierte en parte de la aplicación. Por lo tanto, esta aplicación solo puede ejecutarse en un kernel que esté sincronizado con las interfaces de kernel utilizadas. Si estas interfaces cambian, la aplicación está pisando terreno inestable.

...

Editar:

Parece haber una sobreestimación seria de la estabilidad de la interfaz del kernel de Linux. Vea los cambios / adiciones de la API del kernel de Linux para más detalles. Para resumir:


Las correcciones de errores en glibc no se incluyen en una aplicación vinculada estáticamente cuando actualiza glibc a menos que reconstruya la aplicación.

Además, NSS (Name Service Switch) no funciona a menos que use enlaces dinámicos.


Las razones dadas en otras respuestas son correctas, pero no son la razón más importante.

La razón más importante por la que glibc no debe estar estáticamente vinculado, es que hace un uso interno extenso de dlopen , para cargar módulos NSS ( Name Service Switch ) y conversiones iconv . Los módulos se refieren a las funciones de la biblioteca C. Si el programa principal está vinculado dinámicamente con la biblioteca C, no hay problema. Pero si el programa principal está vinculado estáticamente con la biblioteca C, dlopen tiene que cargar una segunda copia de la biblioteca C para satisfacer los requisitos de carga de los módulos.

Esto significa que su programa "enlazado estáticamente" todavía necesita una copia de libc.so.6 para estar presente en el sistema de archivos, más el NSS o iconv o cualquier módulo en sí, además de otras bibliotecas dinámicas que los módulos puedan necesitar, como ld-linux.so.2 , libresolv.so.2 , etc. Esto no es lo que la gente suele querer cuando vinculan programas estáticamente.

También significa que el programa enlazado estáticamente tiene dos copias de la biblioteca C en su espacio de direcciones, y podrían sbrk sobre sbrk búfer stdout se usará, quién llamará a sbrk con un argumento distinto de cero, ese tipo de cosas. Hay un montón de lógica defensiva dentro de glibc para intentar que esto funcione, pero nunca se ha garantizado que funcione.

Puede pensar que su programa no necesita preocuparse por esto porque nunca llama a getaddrinfo o iconv , pero el soporte local usa iconv internamente, lo que significa que cualquier función stdio.h podría activar una llamada a dlopen , y usted no controle esto, la configuración de la variable de entorno del usuario sí.