DBT库包装符号重定位

Download Report

Transcript DBT库包装符号重定位

库包装符号重定位
张洪娟
2010-12-13
背景
• 在库包装模块中,x86程序依赖的x86库
被包装成loongson本地库,导致符号重定
位出现一些特殊问题。
• 先看一下符号重定位和解析机制
– 符号重定位
– 全局符号介入
符号重定位
• 为什么需要重定位
– 当用gcc编译程序,过程包含预处理、编译、汇编和链接过程
– 目标文件中用到的符号被定义在其他目标文件中,在程序链
接或者装载之前,并不能得到其他模块的符号值,所以需要
进行符号重定位。
• 如何重定位?(x86)
– 每个文件都由重定位表来记录重定位相关的信息,在适当的
时刻(链接、装载或者运行时),链接器会根据重定位项对
符号进行重定位,具体来说就是根据重定位项中的重定位类
型,将符号值填充到相应的重定位入口
– 重定位入口:每个需要被重定位的地方
同名全局量处理
• 问题提出
– 程序的动态链接中,主文件依赖一系列so文件(ldd命令可以看到),这里面定
义了一些同名的全局变量,这些同名全局变量的逻辑语义是一样的,那么符
号的优先级是如何规定的, loader是如何实现的呢?
• 符号优先级
– 全局符号介入:共享对象里面的全局符号被另一个共享对象的全局符号覆盖
的现象
• Linux 动态链接器实现
– 每当文件被装载时,会将其符号表并入到全局符号表
– 定义规则:当一个符号需要被加入全局符号表时,如果相同的全局符号名已
经存在,则后加入的符号被忽略
• 主文件声明但没有定义的全局变量
– x86主文件在自己bss段为声明的全局变量分配内存,也会有重定位项(重定位
类型为R_386_COPY),所以处理方式与库类似,只需根据重定位项进行处理.
符号处理机制
• 在正常的程序链接、装载中,loader会根据上述重定位规则实现符
号解析工作。即,
–
–
X86 loader会实现x86程序的上述功能
Loongson本地的loader也会实现本地文件之间的上述功能
mips主程序
X86主程序
x86
loader
符
号
重
定
位
X86 so1
X86 so2
.
.
.
X86 soN
mips
loader
符
号
重
定
位
mips so1
mips so2
.
.
.
mips soN
问题提出
add on
firefox
dbt
flashplayer
wrapper
lib
• 在库包装模块中,x86程序依赖loongson本地库
– 当x86文件中使用了loongson库中定义的全局量,谁来为它重定位?
– 当x86文件和loongson库中定义了同名的全局变量,谁来决定符号优
先级进而进行符号解析?
– 这是本文要解决的问题
• 在介绍具体实现之前,先介绍一些实现中用到的相关背景知识
相关函数-dlopen(1)
• Dlopen和dlsym
– void *dlopen(const char *filename, int flag)
– void *dlsym(void *handle, const char *symbol)
• The function dlopen() loads the dynamic library file named by the nullterminated string filename and returns an opaque "handle" for the dynamic
library
• The function dlsym() takes a "handle" of a dynamic library returned by
dlopen() and the null-terminated symbol name, returning the address where
that symbol is loaded into memory
• 如果文件名为NULL,那么dlopen返回的是主程序的句柄,也就是说我们可
以在运行时找到全局符号表里面的任意一个符号,并且可以执行它。全
局符号表包括了程序的可执行文件本身、被动态链接器加载到进程中的
所有供想问模块以及在运行时通过dlopen打开的并且使用了
RTLD_GLOBAL方式的模块中的所有符号( RTLD_GLOBAL 表示将被
加载模块的符号合并到全局符号表中)
相关函数-dlopen(2)
• 使用dlopen filename为0特性
– 根据dlopen功能,当filename为0时,我们可以得到loongson本
地全局符号表,包括所有loongson本地主文件及其依赖的本地
库和使用dlopen(设置flag RTLD_GLOBAL)打开因库包装而装
载的本地库中的全局符号
相关定义
• 几个定义
– X86全局符号表:模块中一个记录x86所有符号的符号表,并
且当该值被本地库中的符号重定位时,将该符号从该表中删
除。也就是说,该表记录:
x86所有全局符号-被本地库重定位的符号
– X86重定位表:记录所有x86库文件对本地符号的使用,这些
符号需要本地库中定义的符号去重定位
– 符号处理模块:该模块对遍历到的每个x86符号进行解析,判
断应该用x86符号重定位loongson本地符号,还是用loongson本
地符号去重定位x86相应符号
– 重定位:本文中提到的重定位符号,都是指对需要重定位的
符号进行重定位,这是具体实现中的一个细节
相关模块
• 库包装相关功能
– 在被包装的x86本地库装载时,其相应的本地库不
会被装载,只有在用到的时候才会被装载,也就
X86
是说在x86 loader链接装载x86相关文件时,不会
loader
有loongson本地库被装载
– 我们不妨把x86 load过程作为一个整体,本模块所
有工作都是在该模块之后进行。
X86
Dbt
• 模块调用点
dlopen
dlopen
– X86 loader 刚结束时
– X86 loader结束之后每次dlopen装载x86文件(需要
自己截获x86 dlopen)
调用
点
– X86 loader结束之后dbt每次dlopen打开包装库
调用点-X86 loader结束
• 实现步骤
– 在x86 loader结束之后,根据x86装载序遍历
x86主文件和共享目标文件的符号表,记录
符号信息,形成x86全局符号表
– 调用符号处理模块
符号处理模块
• 对x86全局符号表的每一个符号,使用dlopen\dlsym上
述功能来查找,如果该符号不为空
– 如果该符号在被包装的库里,
该处以及
x86dlope
n调用点
处理
• 则用该符号值去重定位所有当前及以后装载的x86库文件中的该符号(
x86主程序中的符号不需重定位)
• 并将该符号从x86全局符号表中删除
– 如果该符号不在被包装的库里,说明不是插件依赖的本地库
,不需要处理。
• 如果该符号不存在,说明现在已装载的本地库中没有
定义该符号
本地
dlopen调
用点处理
– 如果x86符号值不为0,则用该x86符号的值去重定位所有在此
之后装载的被包装的本地库
– 如果为0,则将该符号添加到x86重定位表中,并在以后装载
的本地包装库中搜索符号来重定位
调用点-x86 dlopen装载文件
• 每当x86文件被dlopen装载,检查其flag是否包含RTLD_GLOBAL
,如果有,将其符号信息添加到x86全局符号表,并将为0的符号
添加到x86重定位表。
• 对该x86库中每一个需要重定位的符号,判断x86全局符号表中是
否存在该符号
– 如果有,应该用x86中符号值来重定位该符号,则x86 loader会进行
定位,不予处理;
– 否则,调用dlopen\dlsym查找本地是否装载了该符号,
• 如果装载了并且在包装库中,则用本地值来重定位该x86符号,并将该符
号从x86全局符号表中删除。
• 否则,会用该值去重定位本地库,这在本地库被dlopen时会检测, 这里
不需处理。
实现-本地dlopen打开包装库
• Dbt 库包装模块使用dlopen(设flag含RTLD_GLOBAL)
打开包装的本地库时,
– 对本地库中每一个需要重定位的符号
• 如果x86全局符号表存在并且不为0,则用x86符号值来重定位该符号值
• 如果x86全局符号表中不存在该值,那应该用本地库中的符号定位该值,
本地loader会帮助处理,我们不予处理。
– 对x86重定位表的每一个符号,使用dlsym检查该库中有没有这
个符号定义,
• 如果有,则用本地符号值来重定位该值,并将该符号从x86重定位表删除
• 如果没有,还会在以后装载本地库时搜索,现在不需处理。
总结
各种情况
已知dlopen\dlsym可以得到已经装载的所有本地包
装库的符号
X86 loader 结束后检测库包装模块dlopen可以得到
此后装载的所有本地包装库
X86 loader 结束之后检测x86 dlopen得到此后装载
的x86文件进而得到其符号
X86主文件及库文件中使用但没定义的符号计入
x86重定位表,并在以后被重定位
X86中的符号在loongson
本地包装库存在
(firefox 装载)
Dlsym可以得到本地库符号的值,使用该值去重定
位装载的x86文件符号(loader之后装载的x86库可
以截获)
X86中的符号在loongson
本地包装库不存在且为0
(flash使用了loongson库
中定义的符号)
这些符号需要从之后装载的loongson本地库得到,
这些符号被加入x86重定位表中,当新装载的
loongson本地包装库中定义了该符号时,就会使用
本地符号值来重定位x86相应符号
X86中的符号在loongson
本地包装库不存在且不
为0
x86主文件及其依赖的x86库中定义了该符号,此时
loongson本地库中不包含该符号,会用x86中该符
号值去重定位所有之后装载的loongson本地库,检
测dbt 库包装模块dlopen即可得到在此之后装载的
本地库