Mr Pang
Mr Pang

Reputation: 1181

__attribute__ ((weak)) not work for global variable

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

Answers (3)

С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

Mike Kinghan
Mike Kinghan

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

Zang MingJie
Zang MingJie

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

Related Questions