全局变量与强符号和弱符号

来源:互联网 发布:java 连接池框架 编辑:程序博客网 时间:2024/05/14 15:04

程序编译的链接阶段中,将函数和变量统称为符号,函数名或者变量名称为符号名。

已初始化的(初始化值不为0)全局变量在连接中为强符号,未初始化或者初始化为0的全局变量为弱符号。在多个源文件中,可以允许声明多个同名的全局变量,但只能有一个初始化,即只允许(同时)存在一个强符号。

例如;Test1.c中:

double g_num = 10;

int test()

{

       printf("test1.c:sizeof(g_num)=%d \n value of g_num = %f\n",sizeof(g_num),g_num);

}

Main.c

int g_num;

int main(void)

{

       printf("main.c:sizeof(g_num) =%d \n value of g_num = %d\n",sizeof(g_num),g_num);

       test();

}

编译: my@ubuntu:~/$gcc haier_main.c test1.c -o testout

/usr/bin/ld: Warning: size of symbol`g_num' changed from 4 in /tmp/ccFWHHgz.o to 8 in /tmp/ccqvBCSU.o

 my@ubuntu:~/ $ ./testout

main.c: sizeof(g_num) =4

 value of g_num = 0

test1.c:sizeof(g_num)= 8

 value of g_num = 10.000000

注意上面的警告;是因为在连接时,保存在符号表中的g_numdouble类型的,main,c中声明的g_num可以看做是对test1.c中的g_num赋值0.,查看符号表如下:

 my@ubuntu:~/ $ readelf -s testout

…….

__libc_start_main@@GLIBC_

   64: 08048660    97 FUNC    GLOBAL DEFAULT   13 __libc_csu_init

   65: 0804a028     0 NOTYPE  GLOBAL DEFAULT  ABS _end

   66: 08048360     0 FUNC    GLOBAL DEFAULT   13 _start

   67: 08048728     4 OBJECT GLOBAL DEFAULT   15 _fp_hw

   68: 0804a020     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start

   69: 08048502   296 FUNC    GLOBAL DEFAULT   13 main

   70: 00000000     0 NOTYPE  WEAK  DEFAULT  UND _Jv_RegisterClasses

   71:0804a018    8 OBJECT  GLOBAL DEFAULT   24 g_num

   72: 080482d4     0 FUNC    GLOBAL DEFAULT   11 _init

73:0804862c   39 FUNC    GLOBAL DEFAULT   13 test

 

另外,如果将test1.c中修改为:

int g_num = 10;

int test()

{

       printf("test1.c:sizeof(g_num)=%d \n value of g_num = %d\n",sizeof(g_num),g_num);

}

Main,c 中修改为:double g_num;

编译后,则打印结果为:

 my@ubuntu:~/ $ gcc  haier_main.c test1.c -o testout

gcc: error: haier_main.c: No such fileor directory

 my@ubuntu:~/ $ gcc  haier_main.c test1.c -o testout

/usr/bin/ld: Warning: alignment 4 ofsymbol `g_num' in /tmp/cc6qqr8P.o is smaller than 8 in /tmp/ccWo2XAC.o

/usr/bin/ld: Warning: size of symbol`g_num' changed from 8 in /tmp/ccWo2XAC.o to 4 in /tmp/cc6qqr8P.o

 my@ubuntu:~/ $ ./testout

main.c: sizeof(g_num) =8

 value of g_num = 0.000000

test1.c:sizeof(g_num)= 4

 value of g_num = 10

 my@ubuntu:~/ $

使用readelf –stestout查看结果如下:

 69: 08048502   296 FUNC   GLOBAL DEFAULT   13 main

   70: 00000000     0 NOTYPE  WEAK  DEFAULT  UND _Jv_RegisterClasses

   71: 0804a018     4 OBJECT  GLOBAL DEFAULT   24 g_num

   72: 080482d4     0 FUNC    GLOBAL DEFAULT   11 _init

73:0804862c   39 FUNC    GLOBAL DEFAULT   13 test

 

以上可以看出,连接器无法判断各个符号的类型是否一致当存在多个同名的符号时,连接后输出文件中该变量所占的空间的大小以输入文件(符号)中最大的那个为准,这也是连接中的common类型的连接规则。但是当多个符号中有一个是强符号时,那么最终输出结果中的符号所占的空间与强符号相同。

再者如果在,main.c中定义了未初始化的全局变量,在可执行文件中可以发现已经为这些变量分配了虚拟空间的地址:

double g_num;

int g_flag;

int g_flag1;

int main(void)…

 my@ubuntu:~/ $ readelf -s testout

Symbol table'.dynsym' contains 6 entries:

   Num:   Value  Size Type    Bind  Vis      Ndx Name

    ….

    54: 0804a01c     0 NOTYPE GLOBAL DEFAULT  ABS _edata

    55: 0804a024     4 OBJECT GLOBAL DEFAULT   25 g_flag

    ……

    72: 0804a018     4 OBJECT GLOBAL DEFAULT   24 g_num

    73: 0804a028     4 OBJECT GLOBAL DEFAULT   25 g_flag1

    74: 080482d4     0 FUNC   GLOBAL DEFAULT   11 _init

    75: 0804862c    39 FUNC   GLOBAL DEFAULT   13 test

注意其中第二列表示的在可执行文件加载时的虚拟空间的地址(即程序在进程所使用的虚拟地址),在Linuxelf可执行文件默认从地址0x08048000开始分配。

未初始化的全局变量或静态变量在编译的时候不会分配内存,可能在加载的时候会为之分配。但是,对于已经初始化的全局或静态变量在编译的时候就需要为之分配内存保存那些初始化的值,这时它们一般会被编译进data段(在linux下),这时这些变量所占用的空间也就被分配了,在加载的时候,data段会被整个加载入内存,因此其对应的空间也被加载到了内存,而不是在堆中再进行分配,堆中都是用mallocnew之类的动态申请的,而不是编译时候就占用的。

0 0
原创粉丝点击