How Linkers Resolve Global Symbols Defined at Multiple Places?

16 Jun, 2022
At compile time, the compiler exports each global symbol to the assembler as either strong or weak, and the assembler encodes this information implicitly in the symbol table of the relocatable object file. Functions and initialized global variables get strong symbols. Uninitialized global variables get weak symbols. For the following example programs, buf, bufp0, main, and swap are strong symbols; bufp1 is a weak symbol. 
C
/* main.c */ void swap(); int buf[2] = {1, 2}; int main() {   swap();   return 0; }   /* swap.c */ extern int buf[];   int *bufp0 = &buf[0]; int *bufp1;   void swap() {   int temp;     bufp1 = &buf[1];   temp = *bufp0;   *bufp0 = *bufp1;   *bufp1 = temp;}
Given this notion of strong and weak symbols, Unix linkers use the following rules for dealing with multiple defined symbols: Rule 1: Multiple strong symbols (with same variable name) are not allowed. Rule 2: Given a strong symbol and multiple weak symbols, choose the strong symbol. Rule 3: Given multiple weak symbols, choose any of the weak symbols. For example, suppose we attempt to compile and link the following two C modules: 
C
/* foo1.c */      int main()         {                    return 0;      }                   /* bar1.c */int main(){  return 0;}
In this case, the linker will generate an error message because the strong symbol main is defined multiple times (rule 1):
$ gcc foo1.c bar1.c
/tmp/cca015022.o: In function ‘main’:
/tmp/cca015022.o(.text+0x0): multiple definition of ‘main’
/tmp/cca015021.o(.text+0x0): first defined here
Similarly, the linker will generate an error message for the following modules because the strong symbol x is defined twice (rule 1): 
C
/* foo2.c */int x = 15213;int main(){  return 0;}  /* bar2.c */int x = 15213;void f(){}
However, if x is uninitialized in one module, then the linker will quietly choose the strong symbol defined in the other (rule 2) as is the case in following program: 
C++
C
/* foo3.c */#include <iostream> void f(void); int x = 15213; int main(){  f();  std::cout << "x = " << x << std::endl;  return 0;}  /* bar3.c */int x;void f(){  x = 15212;}
/* foo3.c */#include <stdio.h>void f(void); int x = 15213; int main(){  f();  printf("x = %d\n", x);  return 0;}  /* bar3.c */int x;void f(){  x = 15212;}
At run time, function f() changes the value of x from 15213 to 15212, which might come as a unwelcome surprise to the author of function main! Notice that the linker normally gives no indication that it has detected multiple definitions of x.
$ gcc -o gfg foo3.c bar3.c
$ ./gfg
x = 15212
The same thing can happen if there are two weak definitions of x (rule 3): 
C
/*a.c*/#include <stdio.h>void b(void); int x;int main(){    x = 2016;    b();    printf("x = %d ",x);    return 0;}/*b.c*/#include <stdio.h> int x; void b(){    x = 2017;     }
The application of rules 2 and 3 can introduce some insidious run-time bugs that are incomprehensible to the unwary programmer, especially if the duplicate symbol definitions have different types. Example : “x” is defined as an int in one module and a double in another. 
C
/*a.c*/#include <stdio.h>void b(void); int x = 2016;int y = 2017;int main(){    b();    printf("x = 0x%x y = 0x%x \n", x, y);    return 0;}/*b.c*/double x; void b(){    x = -0.0;}
Execution:
$ gcc a.c b.c -o geeksforgeeks
$ ./geeksforgeeks
x = 0x0 y = 0x80000000
This is a subtle and nasty bug, especially because it occurs silently, with no warning from the compilation system, and because it typically manifests itself much later in the execution of the program, far away from where the error occurred. In a large system with hundreds of modules, a bug of this kind is extremely hard to fix, especially because many programmers are not aware of how linkers work. When in doubt, invoke the linker with a flag such as the gcc -fno-common flag, which triggers an error if it encounters multiple defined global symbols. Source : http://csapp.cs.cmu.edu/public/ch7-preview.pdf This article is contributed by Sahil Rajput . If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
Pankaj_KS
sarajadhav12052009
C-Variable Declaration and Scope
C Language
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Substring in C++
Function Pointer in C
Different Methods to Reverse a String in C++
std::string class in C++
Unordered Sets in C++ Standard Template Library
Enumeration (or enum) in C
What is the purpose of a function prototype?
C Language Introduction
Memory Layout of C Programs
Command line arguments in C/C++