Reputation: 1181
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 $
Upvotes: 4
Views: 3170
Reputation: 61
Сompiler or linker builds files from the command line in reverse order. In other words, files with ((weak)) should be located earlier in the command line than dynamic ones.
Upvotes: 0
Reputation: 61397
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.
Upvotes: 4
Reputation: 5275
The symbol is resolved at link stage, during the link stage only the weak symbol aaaaa = 8
is visible.
If the symbol can be resolved in the link stage, it won't generate a relocation entry, then nothing will happen at load stage
There are no aaaaa
in the relocation table:
% objdump -R m
m: file format elf64-x86-64
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
0000000000003dc8 R_X86_64_RELATIVE *ABS*+0x0000000000001130
0000000000003dd0 R_X86_64_RELATIVE *ABS*+0x00000000000010f0
0000000000004028 R_X86_64_RELATIVE *ABS*+0x0000000000004028
0000000000003fd8 R_X86_64_GLOB_DAT _ITM_deregisterTMCloneTable
0000000000003fe0 R_X86_64_GLOB_DAT __libc_start_main@GLIBC_2.2.5
0000000000003fe8 R_X86_64_GLOB_DAT __gmon_start__
0000000000003ff0 R_X86_64_GLOB_DAT _ITM_registerTMCloneTable
0000000000003ff8 R_X86_64_GLOB_DAT __cxa_finalize@GLIBC_2.2.5
0000000000004018 R_X86_64_JUMP_SLOT printf@GLIBC_2.2.5
Upvotes: 0