pqy@localhost ~/src/test/a $ cat m.c
#include <stdio.h>
int aaaaa __attribute__ ((weak)) =8;
int main(void){
printf("%d\n", aaaaa);
return 0;
}
pqy@localhost ~/src/test/a $ cat lib.c
int aaaaa = 5;
pqy@localhost ~/src/test/a $ gcc lib.c -fPIC -shared -o libb.so;gcc m.c -o m -L. -lb -Wl,-rpath=$PWD;./m
8
Above is my code and test result. I am confused why it does not work as expected.
Also try function, not work ether. Below is the test result.
pqy@localhost ~/src/test/a $ cat lib.c
int fun() {
return 5;
}
pqy@localhost ~/src/test/a $ cat m.c
#include <stdio.h>
__attribute__((weak)) int fun() {
return 8;
}
int main(void){
printf("%d\n", fun());
return 0;
}
pqy@localhost ~/src/test/a $ gcc lib.c -fPIC -shared -o libb.so;gcc m.c -O0 -o m -L. -lb -Wl,-rpath=$PWD;./m
8
pqy@localhost ~/src/test/a $ ldd m
linux-vdso.so.1 (0x00007ffd819ec000)
libb.so => /home/pqy/src/test/a/libb.so (0x00007f7226738000)
libc.so.6 => /lib64/libc.so.6 (0x00007f7226533000)
/lib64/ld-linux-x86-64.so.2 (0x00007f7226744000)
pqy@localhost ~/src/test/a $
At bottom what you have observed here is just the fact that the linker will not resolve a symbol dynamically if it can resolve it statically. See:
main.c
extern void foo(void);
extern void need_dynamic_foo(void);
extern void need_static_foo(void);
int main(void){
foo();
need_dynamic_foo();
need_static_foo();
return 0;
}
dynamic_foo.c
#include <stdio.h>
void foo(void)
{
puts("foo (dynamic)");
}
void need_dynamic_foo(void)
{
puts(__func__);
}
static_foo.c
#include <stdio.h>
void foo(void)
{
puts("foo (static)");
}
void need_static_foo(void)
{
puts(__func__);
}
Compile the sources so:
$ gcc -Wall -c main.c static_foo.c
$ gcc -Wall -fPIC -c dynamic_foo.c
Make a shared library:
$ gcc -shared -o libfoo.so dynamic_foo.o
And link a program:
$ gcc -o prog main.o static_foo.o libfoo.so -Wl,-rpath=$PWD
It runs like:
$ ./prog
foo (static)
need_dynamic_foo
need_static_foo
So foo
and need_static_foo
were statically resolved to the definitions from static_foo.o
and
the definition of foo
from libfoo.so
was ignored, despite the fact that libfoo.so
was needed and provided the definition of need_dynamic_foo
. It makes no difference
if we change the linkage order to:
$ gcc -o prog main.o libfoo.so static_foo.o -Wl,-rpath=$PWD
$ ./prog
foo (static)
need_dynamic_foo
need_static_foo
It also makes no difference if we replace static_foo.c
with:
static_weak_foo.c
#include <stdio.h>
void __attribute__((weak)) foo(void)
{
puts("foo (static weak)");
}
void need_static_foo(void)
{
puts(__func__);
}
Compile that and relink:
$ gcc -Wall -c static_weak_foo.c
$ gcc -o prog main.o libfoo.so static_weak_foo.o -Wl,-rpath=$PWD
$ ./prog
foo (static weak)
need_dynamic_foo
need_static_foo
Although the definition of foo
in static_weak_foo.c
is now declared weak,
the fact that foo
can be statically resolved to this definition
still preempts any need to resolve it dynamically.
Now if we write another source file containing another strong definition of
foo
:
static_strong_foo.c
#include <stdio.h>
void foo(void)
{
puts("foo (static strong)");
}
and compile it and link as follows:
$ gcc -Wall -c static_strong_foo.c
$ gcc -o prog main.o static_weak_foo.o libfoo.so static_strong_foo.o -Wl,-rpath=$PWD
we see:
$ ./prog
foo (static strong)
need_dynamic_foo
need_static_foo
Now, libfoo.so
still provides the definition of need_dynamic_foo
, because there
is no other; static_weak_foo.o
still provides the only definition of need_static_foo
,
and the definition of foo
in libfoo.so
is still ignored because the symbol
can be statically resolved.
But in this case there are two definitions of foo
in different files that are
available to resolve it statically: the weak definition in static_weak_foo.o
and
the strong definition in static_strong_foo.o
. By the linkage rules that you are
familiar with, the strong definition wins.
If both of these statically linked definitions of foo
were strong, there would of course be a
multiple definition error, just like:
$ gcc -o prog main.o static_foo.o libfoo.so static_strong_foo.o -Wl,-rpath=$PWD
static_strong_foo.o: In function `foo':
static_strong_foo.c:(.text+0x0): multiple definition of `foo'
static_foo.o:static_foo.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
in which the dynamic definition in libfoo.so
plays no part. So you can
be guided by this practical principle: The rules you are familiar with for arbitrating
between weak and strong definitions of the same symbol in a linkage only apply
to rival definitions which would provoke a multiple definition error in the absence
of the weak
attribute.