返回首页   进站必读

13.2 .rodata


13.2 .rodata

.rodata: 只读数据,比如printf语句中的格式串和开关(switch)语句的跳转表。
我们在全局作用域和main函数的局部作用域各定义了一些变量,并且引入了一些新的关键字const、static、register来修饰变量,那么这些变量的存储空间是怎么分配的呢?我们编译之后用readelf命令来查看它的符号表,了解各变量的地址分页。

$gcc main.c -g
$readelf -a a.out

...
49: 0804a01c 4 OBJECT LOCAL DEFAULT 24 b
50: 0804a020 4 OBJECT LOCAL DEFAULT 24 a.1707
...
65: 08048570 4 OBJECT GLOBAL DEFAULT 16 A
66: 0804a018 4 OBJECT GLOBAL DEFAULT 24 a
...
78: 0804a02c 4 OBJECT GLOBAL DEFAULT 25 c

变量A用const修饰,表示A是只读的,不可修改,它被分配的地址是08048570,从readelf的输出可以看到这个地址位于.rodata段:

    Section Headers:
      [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
      [14] .text             PROGBITS        08048390 000390 0001bc 00  AX  0   0 16
      [16] .rodata           PROGBITS        08048568 000568 00001c 00   A  0   0  4
      [24] .data             PROGBITS        0804a010 001010 000014 00  WA  0   0  4
      [25] .bss              NOBITS          0804a024 001024 00000c 00  WA  0   0  4

.rodata段在内存中的地址是0x08048568–0x08048584,在文件中的起始地址为0x568–0x584,我们用hexdump命令来查看这个段的内容:

$hexdump -C a.out:e

...
00000560 5c fe ff ff 59 5b c9 c3 03 00 00 00 01 00 02 00 |\...Y[..........|
00000570 0a 00 00 00 48 65 6c 6c 6f 20 77 6f 72 6c 64 20 |....Hello world |
00000580 25 64 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 |%d..............|
其中0x540地址处的0a 00 00 00就是变量A,字符串的字面值“hello world!\n”分配在.rodata的末尾,字符串字面值是只读的,相当于在全局作用域定义了一个const数组。
在链接时,.rodata和.text合并到Text Segment中,在加载运行时,操作系统将Text Segment设为只读保存起来,防止意外改写。
需要注意的是,象const int A这样的变量在定义时必须进行初始化,因为只有初始化时才有机会给它一个值,一旦定义之后就不能再改写了,也就是不能再赋值了。