今天学习专家c的运行时数据结构,顺便简单地学习了一下nm命令
就目标文件而言,段是二进制文件中的简单区域里面保存了一定信息,section是ELF文件中最小组织单元,一个段包含几个section.
nm命令的作用是显示对象文件,可执行文件以及对象文件库的符号信息.这里只对可执行文件的符号信息进行研究.
以hello world 程序为例
#include <stdio.h> int lemon[1000]; int main(){ printf("Hello World!\n"); return 0; }
/*test.c*/
用gcc test.c 命令编译后默认生成 a.out 这个默认名字的文件是由链接器产生的,之所以叫a.out是因为在遥远的过去,也就是链接器还没有被发明时,汇编产生的程序
就保存在这个a.out文件中(assembler output的缩写),发明链接器后由链接器产生的文件仍然保留了这个称呼.
生成的a.out文件我们先来看看它的大小 即 ls -l a.out 以及它的各个端的大小即 size a.out
再来用nm 命令来看看符号信息 这里用了 -S 选项和 -t FORMAT 选项来方便显示. -S选项是打印定义了的符号的大小的开关. -t FORMAT 是以十进制,十六进制
八进制来打印数字的开关.
观察一下得到的结果第一列为该符号的地址,第三列可能为该符号的大小,可以看到lemon的大小就是4000字节,最后一列为符号的名字
我们来看看第二列有大小的T,t,大小写的B,b等等
这里的大写为GLOBAL小写为LOCAL
b(B)为BSS
d(D)为DATA
t(T)为TEXT
U表示该符号在该文件中是未定义的,即在其他的文件中定义
再来看看当该数组赋值时的情况
文件的大小增加了大约4000字节
而看看可执行的文件中的段,data段大概增加了4000字节,bss段减少了大约4000字节,段总大小几乎不变
所以可以得出结论bss段并不占用可执行文件的任何空间,只是记录其大小.
再来看看把数组声明在函数中会怎样
文件的size比以前少了大约4000字节,段的总的大小也少了4000字节左右
利用nm命令看看
可以发现可执行文件已经没有lemon这个符号了,当对数组进行初始化后也一样.可见在函数中声明的数组并没有存在段中.
最后看看调试选项对可执行文件的影响
可见调试编译对可执行文件大小有影响,但对段的大小并没有影响
总结:
数据段保存在可执行文件中
bss段不保存在可执行文件中
a.out文件大小受调试状态编译的影响,而段不受影响
疑惑:
为什么说文本段是最易受优化措施影响的段.
(看完这章后来试试解决这个疑问)