c/c++ 符号表以及static\const修饰变量

1 符号表

 

2 代码

每个变量都标了号,防止看混了.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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_(intint)
{
    return;
}
 
int _5_cpp_i_func_i_i_(intint)
{
    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_(intint)
{
    return;
}
 
int _0_c_i_func_i_i_(intint)
{
    return 1;
}
}

 

然后编译并查看,注意这里使用 g++

 

然后看一下,下表4代表的段,是那个段:

随便百度一下:rodata的意义同样明显,ro代表read only,即只读数据(const)。

额外补一些:

  1. 常量不一定就放在rodata里,有的立即数直接编码在指令里,存放在代码段(.text)中。
  2. 对于字符串常量,编译器会自动去掉重复的字符串,保证一个字符串在一个可执行文件(EXE/SO)中只存在一份拷贝。
  3. rodata是在多个进程间是共享的,这可以提高空间利用率。

但是这只是编译器说这段不能修改,其实真正强制这个段的内容不能更改的是操作系统在分配页的时候,给页加上的属性.

 

如果使用gcc编译:

 

使用gcc 和使用g++ 编译结果居然一样,可见,gcc 编译 的时候也使用了和g++一样的标识符修饰规则.

而extern "C" 的作用,现在变成了,按照以前 gcc 的形式修饰标识符(因为现在gcc 标识符修改规则已经变了)

 

3 综上

static 和 const修饰的全局变量,默认只在本文件中可见.(注意通常是 cc文件,因为.h文件被 include进去了,不存在可不可见了)

 

4 从elf 符号表角度分析

符号表中的每一项表示一个符号的信息.记录在结构体中

1
2
3
4
5
6
7
8
9
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 文件会被展开)

posted @ 2018-05-17 19:36  农民伯伯-Coding  阅读(1659)  评论(0编辑  收藏  举报