3

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 :

  1. 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.

  2. 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 ?

NO3
  • 31
  • 1
  • 3

0 Answers0