1 符号表
2 代码
每个变量都标了号,防止看混了.
int _1_cpp_i_ = 1; const int _2_cpp_c_i_ = 1; static int _2_cpp_s_i_ = 1; void _4_cpp_v_func_i_i_(int, int) { return; } int _5_cpp_i_func_i_i_(int, int) { return 1; } extern "C" { int _6_c_i_ = 1; const int _7_c_c_i_ = 1; static int _8_c_s_i_ = 1; void _9_c_v_func_i_i_(int, int) { return; } int _0_c_i_func_i_i_(int, int) { return 1; } }
然后编译并查看,注意这里使用 g++
然后看一下,下表4代表的段,是那个段:
随便百度一下:rodata的意义同样明显,ro代表read only,即只读数据(const)。
额外补一些:
- 常量不一定就放在rodata里,有的立即数直接编码在指令里,存放在代码段(.text)中。
- 对于字符串常量,编译器会自动去掉重复的字符串,保证一个字符串在一个可执行文件(EXE/SO)中只存在一份拷贝。
- rodata是在多个进程间是共享的,这可以提高空间利用率。
但是这只是编译器说这段不能修改,其实真正强制这个段的内容不能更改的是操作系统在分配页的时候,给页加上的属性.
如果使用gcc编译:
使用gcc 和使用g++ 编译结果居然一样,可见,gcc 编译 的时候也使用了和g++一样的标识符修饰规则.
而extern "C" 的作用,现在变成了,按照以前 gcc 的形式修饰标识符(因为现在gcc 标识符修改规则已经变了)
3 综上
static 和 const修饰的全局变量,默认只在本文件中可见.(注意通常是 cc文件,因为.h文件被 include进去了,不存在可不可见了)
4 从elf 符号表角度分析
符号表中的每一项表示一个符号的信息.记录在结构体中
struct Elf32_Sym { Elf32_Word st_name; /* 符号名,是在字符串表中的下表 */ Elf32_Addr st_value; /* 符号对应的只,可能是个地址,具体跟富豪有关*/ Elf32_Word st_size; /* 符号大小 */ unsigned char st_info; /* 符号绑定信息 */ unsigned char st_other; /* 其他,目前为0,没有使用 */ Elf32_Section st_shndx; /* 符号所在的段 */ };
readelf -s 只是将信息汇总展示而已.
其中于本文有关的就是 st_info 和st_shndx.
前者指明了该标志服是否在文件外可见,后者指明了标识符所在的段,间接指明是否可以修改.
注意,符号表是编译器和连接器之间的约定.连接器在连接符号的时候,如果遇到符号的 st_info 字段表明尽在文件内可见,那么连接器报错,标识找不到标识符(但其实他找到了.恩,真的找到了.)
5 补充
const定义的全局变量不能被其他文件访问,必须加extern 才能被连接.(注意是 cc 文件中,不能在 .h 文件.上面说了 .h 文件会被展开)