动态符号表 (.dynsym) 用来保存与动态链接相关的导入导出符号,不包括模块内部的符号。而 .symtab 则保存所有符号,包括 .dynsym 中的符号。
动态符号表中所包含的符号的符号名保存在动态符号字符串表 .dynstr 中。
使用 readelf 查看 .dynsym 表,如:readelf --dyn-syms libstdc++.so。
可以看到,.dynsym 表包含39项。__cxa_atexit 是一个导入符号,而 __cxa_guard_acquire 则是一个导出符号。搜索 android libstdc++ 库的源码,能找到该导出函数的定义:
书上说很多动态链接的模块同时拥有 .dynsym 和 .symtab 两个表,但我查看了 android 下的几个系统共享库:libc.so、.liblog.so、libm.so、libstdc++.so,都是只有 .dynsym。其实按我的理解,so 库中就是只有 .dynsym 就可以了,用于动态链接时的符号查找和地址重定位。.symtab 中的内部符号,此时已经没什么用了,所以没必要存在 .symtab。
在 android 的 linker 进行符号重定位工作时,首先要在符号表中查找符号。为了加快查找速度,还借助了与符号表相对应的哈希表,哈希表就保存在上图中的 .hash 中。
soinfo_elf_lookup 函数的第1行代码就是拿到 so 库的符号表在内存中的地址。在 soinfo_link_image 函数中,早在重定位工作进行之前,已经从 .dynamic 中读到了符号表的地址并保存在 si->symtab 中了。包括字符串表和符号哈希表都读取并且保存到soinfo结构里了。
这里面 si->symtab 所保存的地址应该就是 so 库中的 .dynsym 加载到内存后的虚拟地址。关于动态段 .dynamic 的细节,以及 android linker 的源码解析后面会再继续写笔记。
学习资料: 《程序员的自我修养——链接、装载和库》