.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 ...其中0x540地址处的0a 00 00 00就是变量A,字符串的字面值“hello world!\n”分配在.rodata的末尾,字符串字面值是只读的,相当于在全局作用域定义了一个const数组。
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..............|