objdump -h test.o
得到elf的各段信息,有大小、文件内偏移量、各段属性等。
objdump -s -d test.o(-s打印十六进制,-d将包含指令的段反汇编)
其中,代码段与数据段分开,且代码段为readonly属性,这样做三个原因:
1.代码段与数据段映射到进程中不同的地址空间;
2.cpu缓存设计成代码缓存与数据缓存分离;
3.代码段可在进程间共享,节省内存。如同个进程多次打开。
size test.o可看主要三段text data bss段的大小。
可写代码确认各段的大小,数据的存放。
常见段:
gcc有扩展机制指定某变量可放入某个段内:
__attribute__((section("some")) int c;
elf文件结构:
readelf -h test.o读ELF Header。
对应的文件头结构定义于代码:
/usr/include/elf.h内。
ELF头16字节魔数。头4为标志ID,用于操作系统加载时判断是否正确的文件类型。第5字节表示是否32字段或64字节。第6字节1小端、2大端。第7字节版本号。后9字节无用。
DEL+“ELF”
头中TYPE,可重定向.o;可执行;共享目标文件.so。
机器类型指出何机器运行,段表偏移指出段表所在。
readelf -S test.o读取段表,显示全的段信息。每段有类型和标志,决定本段是什么段。
重定位表.rel.test段是需要重定位的东西存的地方;
字符串表分一般的.strtab和段的.shstrtab,前者存正常,后者存段表中的,如段名,这个段在ELF文件头中有起始偏移。
符号表:.symtab
符号,是链接的关键因素。符号表中记录的值,就是代码或函数的地址。 nm test.o读取符号表。
符号类型与绑定信息说明了符号的类型。
readelf -s test.o显示符号表相关。
符号名称:
早期变量名即符号名,这样会造成符号冲突。后来C规定foo变成符号时为_foo。当前gcc默认不加_foo,只有vc加。而c++为解决重载、不同类问题引入了函数签名,使符号看上去复杂,可用c++filt还原。
因此,在c++链接c库时,符号名称不一致,所以引入extern "C"。代码中一般判断__cplusplus来处理。
强符号、弱符号:
函数、初始化的全局变量为强符号,未初始化的全局变量为弱。也可__attrbute__((weak))强行定位弱符号。
链接时强弱符号处理规则:
1. 强符号只能有一个;2. 强弱共存取强;3. 多个弱符号取大的。
可用于在库文件中定义的函数定义成弱符号时,被用户代码覆盖而不报错。
强引用、弱引用:
强引用指链接时,未找到符号定义会报错的引用。弱引用则找不到符号定义时设为特殊值,一般是0。
gcc可__attribute__((weakref))指定为弱引用。
可用于判断是否链接了外部库,如lpthread。
strip test.o用于去除目标文件中的调试信息。
阅读(990) | 评论(0) | 转发(0) |