Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

It seems uninitialized global variable is treated as weak symbol in Gcc. What is the reason behind this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
192 views
Welcome To Ask or Share your Answers For Others

1 Answer

gcc, in C mode:

Uninitialised globals which are not declared extern are treated as "common" symbols, not weak symbols.

Common symbols are merged at link time so that they all refer to the same storage; if more than one object attempts to initialise such a symbol, you will get a link-time error. (If they aren't explicitly initialised anywhere, they will be placed in the BSS, i.e. initialised to 0.)

gcc, in C++ mode:

Not the same - it doesn't do the common symbols thing. "Uninitialised" globals which are not declared extern are implicitly initialised to a default value (0 for simple types, or default constructor).


In either case, a weak symbol allows an initialised symbol to be overridden by a non-weak initialised symbol of the same name at link time.


To illustrate (concentrating on the C case here), I'll use 4 variants of a main program, which are all the same except for the way that global is declared:

  1. main_init.c:

    #include <stdio.h>
    
    int global = 999;
    
    int main(void) { printf("%d
    ", global); return 0; }
    
  2. main_uninit.c, which omits the initialisation:

    #include <stdio.h>
    
    int global;
    
    int main(void) { printf("%d
    ", global); return 0; }
    
  3. main_uninit_extern.c, which adds the extern keyword:

    #include <stdio.h>
    
    extern int global;
    
    int main(void) { printf("%d
    ", global); return 0; }
    
  4. main_init_weak.c, which initialises global and declares it to be a weak symbol:

    #include <stdio.h>
    
    int global __attribute__((weak)) = 999;
    
    int main(void) { printf("%d
    ", global); return 0; }
    

and another_def.c which initialises the same global:

int global = 1234;

Using main_uninit.c on its own gives 0:

$ gcc -o test main_uninit.c && ./test
0

but when another_def.c is included as well, global is explicitly initialised and we get the expected result:

$ gcc -o test main_uninit.c another_def.c && ./test
1234

(Note that this case fails instead if you're using C++.)

If we try with both main_init.c and another.def.c instead, we have 2 initialisations of global, which won't work:

$ gcc -o test main_init.c another_def.c && ./test
/tmp/cc5DQeaz.o:(.data+0x0): multiple definition of `global'
/tmp/ccgyz6rL.o:(.data+0x0): first defined here
collect2: ld returned 1 exit status

main_uninit_extern.c on its own won't work at all - the extern keyword causes the symbol to be an ordinary external reference rather than a common symbol, so the linker complains:

$ gcc -o test main_uninit_extern.c && ./test
/tmp/ccqdYUIr.o: In function `main':
main_uninit_extern.c:(.text+0x12): undefined reference to `global'
collect2: ld returned 1 exit status

It works fine once the initialisation from another_def.c is included:

$ gcc -o test main_uninit_extern.c another_def.c && ./test
1234

Using main_init_weak.c on its own gives the value we initialised the weak symbol to (999), as there is nothing to override it:

$ gcc -o test main_init_weak.c && ./test
999

But pulling in the other definition from another_def.c does work in this case, because the strong definition there overrides the weak definition in main_init_weak.c:

$ gcc -o test main_init_weak.c another_def.c && ./test
1234

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...