3.6 调试信息
目标文件里面还有可能保存的是调试信息。几乎所有现代的编译器都支持源代码级别的调试,比如我们可以在函数里面设置断点,可以监视变量变化,可以单步行进等,前提是编译器必须提前将源代码与目标代码之间的关系等,比如目标代码中的地址对应源代码中的哪一行、函数和变量的类型、结构体的定义、字符串保存到目标文件里面。甚至有些高级的编译器和调试器支持查看STL容器的内容,即程序员在调试过程中可以直接观察STL容器中的成员的值。
如果我们在GCC编译时加上"-g"参数,编译器就会在产生的目标文件里面加上调试信息,我们通过readelf等工具可以看到,目标文件里多了很多"debug"相关的段:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
...
[ 4] .debug_abbrev PROGBITS 00000000 000040 000034 00 0 0 1
[ 5] .debug_info PROGBITS 00000000 000074 0000af 00 0 0 1
[ 6] .rel.debug_info REL 00000000 000738 000038 08 9 5 4
[ 7] .debug_line PROGBITS 00000000 000123 000037 00 0 0 1
[ 8] .rel.debug_line REL 00000000 000770 000008 08 19 7 4
[ 9] .debug_frame PROGBITS 00000000 00015c 000034 00 0 0 4
[10] .rel.debug_frame REL 00000000 000778 000010 08 19 9 4
[11] .debug_loc PROGBITS 00000000 000190 00002c 00 0 0 1
[12] .debug_pubnames PROGBITS 00000000 0001bc 00001a 00 0 0 1
[13] .rel.debug_pubnam REL 00000000 000788 000008 08 19 12 4
[14] .debug_aranges PROGBITS 00000000 0001d6 000020 00 0 0 1
[15] .rel.debug_arange REL 00000000 000790 000010 08 19 14 4
...
这些段中保存的就是调试信息。现在的ELF文件采用一个叫DWARF(Debug With Arbitrary Record Format)的标准的调试信息格式,现在该标准已经发展到了第三个版本,即DWARF 3,由DWARF标准委员会由2006年颁布。Microsoft也有自己相应的调试信息格式标准,叫CodeView。关于调试信息的具体内容我们在这里不再详细展开了,它将是另外一个独立的并且很大的话题,对我们理解整个系统软件的意义不大,有兴趣的读者可以参照相应的格式标准。但是值得一提的是,调试信息在目标文件和可执行文件中占用很大的空间,往往比程序的代码和数据本身大好几倍,所以当我们开发完程序并要将它发布的时候,须要把这些对于用户没有用的调试信息去掉,以节省大量的空间。在Linux下,我们可以使用"strip"命令来去掉ELF文件中的调试信息:
$strip foo