【全局变量】编译期间和链接期间全局变量的相关研究

编译期间和链接期间全局变量的研究

全局变量

一般我们认为未初始化的全局变量和静态局部变量都是存放在.bss段中,初始化了的全局变量和静态局部变量存放在.data段中。

实验环境
host:Ubuntu 20.04
gcc:gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1)

//a.c

int a;
int b=10;

extern int c;
int main(void)
{
    static int static_init_var = 10;
    static int static_uninit_var;
	swap(&c,&b);
}
//b.c
int c = 100;
void swap(int *a, int *b)
{
	int *temp;
	temp = a;
	a = b;
	b = temp;
}
gcc -c a.c -fno-stack-protector
gcc -c b.c -fno-stack-protector
ld a.o b.o -e main -o ab

现在来看一下三个elf文件的符号信息。

$ readelf -s a.o b.o ab

File: a.o

Symbol table '.symtab' contains 17 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS a.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     4 OBJECT  LOCAL  DEFAULT    4 static_uninit_var.1917
     6: 0000000000000004     4 OBJECT  LOCAL  DEFAULT    3 static_init_var.1916
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     9: 0000000000000000     0 SECTION LOCAL  DEFAULT    8 
    10: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
    11: 0000000000000004     4 OBJECT  GLOBAL DEFAULT  COM a
    12: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 b
    13: 0000000000000000    39 FUNC    GLOBAL DEFAULT    1 main
    14: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND c
    15: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
    16: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND swap

File: b.o

Symbol table '.symtab' contains 11 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS b.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    2 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     9: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    2 c
    10: 0000000000000000    43 FUNC    GLOBAL DEFAULT    1 swap

File: ab

Symbol table '.symtab' contains 17 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000004001c8     0 SECTION LOCAL  DEFAULT    1 
     2: 0000000000401000     0 SECTION LOCAL  DEFAULT    2 
     3: 0000000000402000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000404000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000404008     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     7: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS a.c
     8: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS b.c
     9: 0000000000404000     4 OBJECT  GLOBAL DEFAULT    4 b
    10: 0000000000401027    55 FUNC    GLOBAL DEFAULT    2 swap
    11: 0000000000404004     4 OBJECT  GLOBAL DEFAULT    4 c
    12: 0000000000404008     0 NOTYPE  GLOBAL DEFAULT    5 __bss_start
    13: 0000000000401000    39 FUNC    GLOBAL DEFAULT    2 main
    14: 0000000000404008     0 NOTYPE  GLOBAL DEFAULT    4 _edata
    15: 0000000000404010     0 NOTYPE  GLOBAL DEFAULT    5 _end
    16: 0000000000404008     4 OBJECT  GLOBAL DEFAULT    5 a

readelf -s 输出的Ndx列表示的是所在段的编号,可以通过readelf -t来查看。

$ readelf -t a.o b.o ab

File: a.o
There are 13 section headers, starting at offset 0x3b8:

Section Headers:
  [Nr] Name
       Type              Address          Offset            Link
       Size              EntSize          Info              Align
       Flags
  [ 0] 
       NULL             0000000000000000  0000000000000000  0
       0000000000000000 0000000000000000  0                 0
       [0000000000000000]: 
  [ 1] .text
       PROGBITS         0000000000000000  0000000000000040  0
       0000000000000027 0000000000000000  0                 1
       [0000000000000006]: ALLOC, EXEC
  [ 2] .rela.text
       RELA             0000000000000000  00000000000002e8  10
       0000000000000048 0000000000000018  1                 8
       [0000000000000040]: INFO LINK
  [ 3] .data
       PROGBITS         0000000000000000  0000000000000068  0
       0000000000000008 0000000000000000  0                 4
       [0000000000000003]: WRITE, ALLOC
  [ 4] .bss
       NOBITS           0000000000000000  0000000000000070  0
       0000000000000004 0000000000000000  0                 4
       [0000000000000003]: WRITE, ALLOC
  [ 5] .comment
       PROGBITS         0000000000000000  0000000000000070  0
       000000000000002c 0000000000000001  0                 1
       [0000000000000030]: MERGE, STRINGS
  [ 6] .note.GNU-stack
       PROGBITS         0000000000000000  000000000000009c  0
       0000000000000000 0000000000000000  0                 1
       [0000000000000000]: 
  [ 7] .note.gnu.property
       NOTE             0000000000000000  00000000000000a0  0
       0000000000000020 0000000000000000  0                 8
       [0000000000000002]: ALLOC
  [ 8] .eh_frame
       PROGBITS         0000000000000000  00000000000000c0  0
       0000000000000038 0000000000000000  0                 8
       [0000000000000002]: ALLOC
  [ 9] .rela.eh_frame
       RELA             0000000000000000  0000000000000330  10
       0000000000000018 0000000000000018  8                 8
       [0000000000000040]: INFO LINK
  [10] .symtab
       SYMTAB           0000000000000000  00000000000000f8  11
       0000000000000198 0000000000000018  11                8
       [0000000000000000]: 
  [11] .strtab
       STRTAB           0000000000000000  0000000000000290  0
       0000000000000055 0000000000000000  0                 1
       [0000000000000000]: 
  [12] .shstrtab
       STRTAB           0000000000000000  0000000000000348  0
       000000000000006c 0000000000000000  0                 1
       [0000000000000000]: 

File: b.o
There are 12 section headers, starting at offset 0x290:

Section Headers:
  [Nr] Name
       Type              Address          Offset            Link
       Size              EntSize          Info              Align
       Flags
  [ 0] 
       NULL             0000000000000000  0000000000000000  0
       0000000000000000 0000000000000000  0                 0
       [0000000000000000]: 
  [ 1] .text
       PROGBITS         0000000000000000  0000000000000040  0
       000000000000002b 0000000000000000  0                 1
       [0000000000000006]: ALLOC, EXEC
  [ 2] .data
       PROGBITS         0000000000000000  000000000000006c  0
       0000000000000004 0000000000000000  0                 4
       [0000000000000003]: WRITE, ALLOC
  [ 3] .bss
       NOBITS           0000000000000000  0000000000000070  0
       0000000000000000 0000000000000000  0                 1
       [0000000000000003]: WRITE, ALLOC
  [ 4] .comment
       PROGBITS         0000000000000000  0000000000000070  0
       000000000000002c 0000000000000001  0                 1
       [0000000000000030]: MERGE, STRINGS
  [ 5] .note.GNU-stack
       PROGBITS         0000000000000000  000000000000009c  0
       0000000000000000 0000000000000000  0                 1
       [0000000000000000]: 
  [ 6] .note.gnu.property
       NOTE             0000000000000000  00000000000000a0  0
       0000000000000020 0000000000000000  0                 8
       [0000000000000002]: ALLOC
  [ 7] .eh_frame
       PROGBITS         0000000000000000  00000000000000c0  0
       0000000000000038 0000000000000000  0                 8
       [0000000000000002]: ALLOC
  [ 8] .rela.eh_frame
       RELA             0000000000000000  0000000000000210  9
       0000000000000018 0000000000000018  7                 8
       [0000000000000040]: INFO LINK
  [ 9] .symtab
       SYMTAB           0000000000000000  00000000000000f8  10
       0000000000000108 0000000000000018  9                 8
       [0000000000000000]: 
  [10] .strtab
       STRTAB           0000000000000000  0000000000000200  0
       000000000000000a 0000000000000000  0                 1
       [0000000000000000]: 
  [11] .shstrtab
       STRTAB           0000000000000000  0000000000000228  0
       0000000000000067 0000000000000000  0                 1
       [0000000000000000]: 

File: ab
There are 10 section headers, starting at offset 0x3250:

Section Headers:
  [Nr] Name
       Type              Address          Offset            Link
       Size              EntSize          Info              Align
       Flags
  [ 0] 
       NULL             0000000000000000  0000000000000000  0
       0000000000000000 0000000000000000  0                 0
       [0000000000000000]: 
  [ 1] .note.gnu.property
       NOTE             00000000004001c8  00000000000001c8  0
       0000000000000020 0000000000000000  0                 8
       [0000000000000002]: ALLOC
  [ 2] .text
       PROGBITS         0000000000401000  0000000000001000  0
       000000000000005e 0000000000000000  0                 1
       [0000000000000006]: ALLOC, EXEC
  [ 3] .eh_frame
       PROGBITS         0000000000402000  0000000000002000  0
       0000000000000058 0000000000000000  0                 8
       [0000000000000002]: ALLOC
  [ 4] .data
       PROGBITS         0000000000404000  0000000000003000  0
       0000000000000008 0000000000000000  0                 4
       [0000000000000003]: WRITE, ALLOC
  [ 5] .bss
       NOBITS           0000000000404008  0000000000003008  0
       0000000000000008 0000000000000000  0                 4
       [0000000000000003]: WRITE, ALLOC
  [ 6] .comment
       PROGBITS         0000000000000000  0000000000003008  0
       000000000000002b 0000000000000001  0                 1
       [0000000000000030]: MERGE, STRINGS
  [ 7] .symtab
       SYMTAB           0000000000000000  0000000000003038  8
       0000000000000198 0000000000000018  9                 8
       [0000000000000000]: 
  [ 8] .strtab
       STRTAB           0000000000000000  00000000000031d0  0
       000000000000002d 0000000000000000  0                 1
       [0000000000000000]: 
  [ 9] .shstrtab
       STRTAB           0000000000000000  00000000000031fd  0
       0000000000000052 0000000000000000  0                 1
       [0000000000000000]:

经过这里可以分析,在编译之后未链接之前,已经初始化的全局变量和静态局部变量都是在.data段,未经初始化的静态局部变量是在.bss段,

而未经初始化的全局变量是放在common块,common块最早来源于Fortran,早期Fortran没有动态分配空间的机制,程序员必须事先声明它所需的零时使用空间大小。Fortran把这种空间叫做common块 —《程序员的自我修养》
gcc的-fno-common允许我们把所有未初始化的全局变量不以common块的形式处理,或者以int global attribute((nocommon));一旦一个未初始化的全局变量不是以common块的形式存在,那么他就相当于一个强符号,如果其他目标文件中还有同一个变量的强符号定义,链接时就会发生符号重定义的错误。

但是在链接之后,通过readelf -s ab可以看出初始化的全局变量和静态局部变量依旧在.data段,未经初始化的全局变量和静态局部变量都在.bss段了。

原因分析

这里涉及到弱符号与强符号的概念,在链接期间,如果有多个同名的强符号则会出现重定义的错误,如果有多个同名的弱符号只有一个强符号,则以强符号的空间大小来分配空间,如果有没有强符号,则以最大的弱符号为主来分配空间。未初始化的全局变量就是一个弱符号,所以在编译期间,它并没有被放在.bss段,原因是在链接的时候有可能会遇到其他编译单元的同名符号,编译期间无法确定其分配大小,但是再链接期间,所有编译单元各段都组合好,此时可以确定符号所需要的确定空间,链接结束就会将其放入.bss段中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值