Recently I 'm studying the linking process and when it comes to weak symbol, my textbook give a code below to demonstrate how to use __attribute__((weakref)) to declare a weak reference to external function:
//pthread.c
#include <stdio.h>
#include <pthread.h>
int pthread_create(
pthread_t*,
const pthread_attr_t*,
void* (*)(void*),
void*
)__attribute__((weak));
int main()
{
if(pthread_create){
printf("This is multi-thread version\n");
}else{
printf("This is single-thread version!\n");
}
}
Then the author use different ways of linking ,which gives the result:
$ gcc pthread.c -o pt
$ ./pt
This is single-thread version!
$ gcc pthread.c -lpthread -o pt
$ ./pt
This is multi-thread version!
I reproduced the same procedure on my machine, but both results give This is single-thread version!
I tried to find out what 's going on here, but I quickly stuck into two problem :
I think it might be that the author mistakenly write __attribute((weak))__instead of __attribute__((weakref))__ here. Because if one module declare a weak symbol, the linker would not find the definition of the symbol in the library during the static linking process. Considering that GCC use dynamic linking by default, I use static linking to verify that :
$ gcc -c pthread.c
$ nm pthread.o
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T main
w pthread_create
U puts
$ gcc -static pthread.c -lpthread -o pt
$ nm pt | grep 'pthread_create'
$
the symbol 'pthread_create' do not appear in the symbol table.
Now I use __attribute((weakref))__ to reproduce the procedures.
//pthread.c modified
#include <stdio.h>
#include <pthread.h>
static int pthread_create_dup(
pthread_t*,
const pthread_attr_t*,
void* (*)(void*),
void*
)__attribute__((weakref,alias("pthread_create")));
int main()
{
if(pthread_create_dup){
printf("This is multi-thread version!\n");
}else{
printf("This is single-thread version!\n");
}
}
still, after compiling and linking, the result is This is single-thread version!
$ gcc -static pthread.c -lpthread -o pt
$ nm pt | grep 'pthread_create'
$
I make another sample to simulate above:
test.c:
extern int foo(int a,int b);
static int foo_dup(int a,int b) __attribute__((weakref,alias("foo")));
int main(){
if(foo_dup){
printf("foo is linked\n");
}else{
printf("foo isn't linked\n");
}
}
ref_foo.c
int foo(int a ,int b){
return a+b;
}
Then compile those two:
$ gcc -c ref_foo.c test.c
$ ar rcs libfoo.a ref_foo.o
$ gcc -static test.o libfoo.a -o test_withlib
$ ./test_withlib
foo isn't linked
$ gcc -static test.o ref_foo.o -o test_withoutlib
$ ./test_withoutlib
foo is linked
So why would this happen? It's apparently I cannot extract pthread_create.o from libpthread.o and simply gcc pthread.c pthread_create.o -o pt.How to correctly implement pthread.c so it will print This is multi-thread version! when linking to the libpthread ?
I'm also studying the linking process, you can use the follow command:
gcc pthread.c -Wl,--no-as-needed -lpthread -o pt
-Wl,--no-as-needed is a linker option that means disable the linker optimization.
by the way, you should use __attribute((weak))__.
you can use the ldd command to check the result:
$ gcc pthread.c -lpthread -o pt && ldd pt
linux-vdso.so.1 (0x00007ffd0c7ec000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb3f7a07000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb3f7ffa000)
$ gcc pthread.c -Wl,--no-as-needed -lpthread -o pt && ldd pt
linux-vdso.so.1 (0x00007ffe0fff2000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb998dbd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb9989cc000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb9991de000)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With