How to track linker issue for global variable re-defination issue

Viewed 31

I am trying to find the issue with below code, need to know how linker is able to track global variable multiple definition issue in below program, I am not sure much on how linker internally performs checking so requesting help to clarify.

**hello.h**
#ifndef __HELLO_
#define __HELLO_

static int s = 20;
int g = 10;

#endif

**cat hello1.c**
#include <stdio.h>
#include "hello.h"

//int g = 10;

int main()
{
 g++;
 s++;
 printf("g : %d s : %d\n", g, s);
 function();
 return 0;
}

**cat hello2.c**
#include <stdio.h>
#include "hello.h"

//extern int g;

void function()
{
 g++;
 s++;
 printf("g : %d s : %d\n", g, s);
}

**gcc -save-temps hello1.c hello2.c -o hello**
hello2.o:(.data+0x4): multiple definition of `g'
hello1.o:(.data+0x4): first defined here
**collect2: error: ld returned 1 exit status**

I don't need solution to fix this error, I know above program will throw multiple definition error of g as above but can anyone please explain how it tracks this error at linking stage?.

Here is the output of assembly code.

**cat hello1.s**
        .file   "hello1.c"
        .data
        .align 4
        .type   s, @object
        .size   s, 4
s:
        .long   20
        .globl  g
        .align 4
        .type   g, @object
        .size   g, 4
g:
        .long   10
        .section        .rodata
.LC0:
        .string "g : %d s : %d\n"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    g(%rip), %eax
        addl    $1, %eax
        movl    %eax, g(%rip)
        movl    s(%rip), %eax
        addl    $1, %eax
        movl    %eax, s(%rip)
        movl    s(%rip), %edx
        movl    g(%rip), %eax
        movl    %eax, %esi
        movl    $.LC0, %edi
        movl    $0, %eax
        call    printf
        movl    $0, %eax
        call    function
        movl    $0, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
        .section        .note.GNU-stack,"",@progbits



**cat hello2.s**
        .file   "hello2.c"
        .data
        .align 4
        .type   s, @object
        .size   s, 4
s:
        .long   20
        .globl  g
        .align 4
        .type   g, @object
        .size   g, 4
g:
        .long   10
        .section        .rodata
.LC0:
        .string "g : %d s : %d\n"
        .text
        .globl  function
        .type   function, @function
function:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    g(%rip), %eax
        addl    $1, %eax
        movl    %eax, g(%rip)
        movl    s(%rip), %eax
        addl    $1, %eax
        movl    %eax, s(%rip)
        movl    s(%rip), %edx
        movl    g(%rip), %eax
        movl    %eax, %esi
        movl    $.LC0, %edi
        movl    $0, %eax
        call    printf
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   function, .-function
        .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
        .section        .note.GNU-stack,"",@progbits

Please share me the reference if this query is already posted earlier, unable to track the similar link.

1 Answers

Internally compiler generates two distinct object files hello1.o and hello2.o. Each of them exports variable g:

$ readelf hello1.o | grep GLOBAL
     8: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    2 g
$ readelf hello2.o | grep GLOBAL
     10: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    2 g

Linker detects that there is more then one definition of g when building a global symbol table for the executable and reports an error.

Related