¿Cómo hacer que gcc enlace símbolo fuerte en la biblioteca estática para sobrescribir el símbolo débil?
ld weak-linking (2)
Mi problema se puede resumir en lo siguiente:
bar.c :
#include <stdio.h>
void bar() {
printf("bar/n");
}
main.c :
#include <stdio.h>
void __attribute__((weak)) bar() {
printf("foo/n");
}
int main() {
bar();
return 0;
}
Makefile :
all:
gcc -c bar.c
ar -rc libbar.a bar.o
gcc main.c -L. -lbar
Salida :
$ ./a.out
foo
Por lo tanto, la barra de símbolos débil en main.c no se sobrescribe con el símbolo fuerte en bar.c debido a que bar.c está vinculado a main.c en una biblioteca estática libbar.a.
¿Cómo puedo decirle a gcc que haga que el símbolo fuerte en libbar.a sobrescriba el símbolo débil en main.c?
En términos generales: si no pone una implementación débil en su main
, el vinculador lo resolverá por fin en tiempo de ejecución. Pero si lo implementa en main.c
, solo podrá anularlo con un límite fuerte ( bar.c
) al vincular esta estática.
Lea http://www.bottomupcs.com/libraries_and_the_linker.html - contiene muchas cosas interesantes sobre este tema.
Yo mismo he hecho una prueba:
bar.c
#include <stdio.h>
void bar()
{
puts("bar.c: i''m the strong bar()");
}
baz.c
#include <stdio.h>
void __attribute__((weak)) bar()
{
puts("baz.c: i''m the weak bar()");
}
C Principal
#include <stdio.h>
#ifdef V2
void __attribute__((weak)) bar()
{
puts("main: i''m the build in weak bar()");
}
#else
void __attribute__((weak)) bar();
#endif
int main()
{
bar();
return 0;
}
Mi Makefile:
all:
gcc -c -o bar.o bar.c
gcc -shared -fPIC -o libbar.so bar.o
gcc -c -o baz.o baz.c
gcc -shared -fPIC -o libbaz.so baz.o
gcc -o main1 main.c -L. -lbar -lbaz
gcc -o main2 main.c -L. -lbaz -lbar
LD_LIBRARY_PATH=. ./main1 # => bar.c
LD_LIBRARY_PATH=. ./main2 # => baz.c
LD_LIBRARY_PATH=. LD_PRELOAD=libbaz.so ./main1 # => baz.c (!!)
LD_LIBRARY_PATH=. LD_PRELOAD=libbaz.so ./main2 # => baz.c
gcc -o main3 main.c bar.o baz.o
gcc -o main4 main.c baz.o bar.o
./main3 # => bar.c
./main4 # => bar.c
gcc -DV2 -o main5 main.c -L. -lbar -lbaz
gcc -DV2 -o main6 main.c -L. -lbaz -lbar
LD_LIBRARY_PATH=. ./main5 # => main''s implementation
LD_LIBRARY_PATH=. ./main6 # => main''s implementation
gcc -DV2 -o main7 main.c -L. -lbar -lbaz
gcc -DV2 -o main8 main.c -L. -lbaz -lbar
LD_LIBRARY_PATH=. LD_PRELOAD=libbaz.so ./main7 # => main''s implementation
LD_LIBRARY_PATH=. LD_PRELOAD=libbaz.so ./main8 # => main''s implementation
gcc -DV2 -o main9 main.c -L. -lbar -lbaz
gcc -DV2 -o main10 main.c -L. -lbaz -lbar
LD_LIBRARY_PATH=. LD_PRELOAD=libbar.so ./main9 # => main''s implementation
LD_LIBRARY_PATH=. LD_PRELOAD=libbar.so ./main10 # => main''s implementation
gcc -c bar.c
gcc -c baz.c
gcc -o main11 main.c bar.o baz.o
gcc -o main12 main.c baz.o bar.o
./main11 # => bar.c
./main12 # => bar.c
gcc -o main13 -DV2 main.c bar.o baz.o
gcc -o main14 -DV2 main.c baz.o bar.o
./main13 # => bar.c
./main14 # => bar.c
Eche un vistazo a main1 && main2 ... si no pone ninguna implementación débil en main.c
pero mantiene la débil en una biblioteca y la fuerte en otra biblioteca, podrá anular la débil. si la lib fuerte define una fuerte implementación de bar()
.
Estoy sorprendido por la respuesta dada por max.haredoom (y que fue aceptada). La respuesta trata sobre bibliotecas compartidas y enlaces dinámicos, mientras que la pregunta era claramente sobre el comportamiento de los enlaces estáticos utilizando bibliotecas estáticas. Creo que esto es engañoso.
Al vincular bibliotecas estáticas, a ld
no le importan los símbolos débiles / fuertes de manera predeterminada : simplemente resuelve un símbolo indefinido en un primer símbolo encontrado (por lo tanto, el orden de las bibliotecas estáticas en la línea de comandos es importante).
Sin embargo, este comportamiento predeterminado se puede cambiar utilizando la opción --whole-archive
. Si reescribe su último paso en Makefile de la siguiente manera:
gcc main.c -L. -Wl,--whole-archive -lbar -Wl,--no-whole-archive
Entonces verás:
$ ./a.out
bar
En pocas palabras, --whole-archive
obliga al enlazador a escanear todos sus símbolos (incluidos los ya resueltos). Si hay un símbolo fuerte que ya fue resuelto por un símbolo débil (como en nuestro caso), el símbolo fuerte anulará al débil.
También vea una excelente publicación sobre bibliotecas estáticas y su proceso de enlace "Orden de biblioteca en enlace estático" por Eli Bendersky y esta pregunta de SO .