1 / 15

库包装符号重定位

库包装符号重定位. 张洪娟 2010-12-13. 背景. 在库包装模块中, x86 程序依赖的 x86 库被包装成 loongson 本地库,导致符号重定位出现一些特殊问题。 先看一下符号重定位和解析机制 符号重定位 全局符号介入. 符号重定位. 为什么需要重定位 当用 gcc 编译程序,过程包含预处理、编译、汇编和链接过程 目标文件中用到的符号被定义在其他目标文件中,在程序链接或者装载之前,并不能得到其他模块的符号值,所以需要进行符号重定位。 如何重定位?( x86 )

myron
Download Presentation

库包装符号重定位

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 库包装符号重定位 张洪娟 2010-12-13

  2. 背景 • 在库包装模块中,x86程序依赖的x86库被包装成loongson本地库,导致符号重定位出现一些特殊问题。 • 先看一下符号重定位和解析机制 • 符号重定位 • 全局符号介入

  3. 符号重定位 • 为什么需要重定位 • 当用gcc编译程序,过程包含预处理、编译、汇编和链接过程 • 目标文件中用到的符号被定义在其他目标文件中,在程序链接或者装载之前,并不能得到其他模块的符号值,所以需要进行符号重定位。 • 如何重定位?(x86) • 每个文件都由重定位表来记录重定位相关的信息,在适当的时刻(链接、装载或者运行时),链接器会根据重定位项对符号进行重定位,具体来说就是根据重定位项中的重定位类型,将符号值填充到相应的重定位入口 • 重定位入口:每个需要被重定位的地方

  4. 同名全局量处理 • 问题提出 • 程序的动态链接中,主文件依赖一系列so文件(ldd命令可以看到),这里面定义了一些同名的全局变量,这些同名全局变量的逻辑语义是一样的,那么符号的优先级是如何规定的, loader是如何实现的呢? • 符号优先级 • 全局符号介入:共享对象里面的全局符号被另一个共享对象的全局符号覆盖的现象 • Linux 动态链接器实现 • 每当文件被装载时,会将其符号表并入到全局符号表 • 定义规则:当一个符号需要被加入全局符号表时,如果相同的全局符号名已经存在,则后加入的符号被忽略 • 主文件声明但没有定义的全局变量 • x86主文件在自己bss段为声明的全局变量分配内存,也会有重定位项(重定位类型为R_386_COPY),所以处理方式与库类似,只需根据重定位项进行处理.

  5. 符号处理机制 • 在正常的程序链接、装载中,loader会根据上述重定位规则实现符号解析工作。即, • X86 loader会实现x86程序的上述功能 • Loongson本地的loader也会实现本地文件之间的上述功能 mips主程序 符号重定位 X86主程序 符号重定位 mips so1 X86 so1 mips loader mips so2 x86 loader X86 so2 . . . . . . mips soN X86 soN

  6. 问题提出 • 在库包装模块中,x86程序依赖loongson本地库 • 当x86文件中使用了loongson库中定义的全局量,谁来为它重定位? • 当x86文件和loongson库中定义了同名的全局变量,谁来决定符号优先级进而进行符号解析? • 这是本文要解决的问题 • 在介绍具体实现之前,先介绍一些实现中用到的相关背景知识 add on firefox dbt flashplayer wrapper lib

  7. 相关函数-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 null-terminated 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 表示将被加载模块的符号合并到全局符号表中)

  8. 相关函数-dlopen(2) • 使用dlopen filename为0特性 • 根据dlopen功能,当filename为0时,我们可以得到loongson本地全局符号表,包括所有loongson本地主文件及其依赖的本地库和使用dlopen(设置flag RTLD_GLOBAL)打开因库包装而装载的本地库中的全局符号

  9. 相关定义 • 几个定义 • X86全局符号表:模块中一个记录x86所有符号的符号表,并且当该值被本地库中的符号重定位时,将该符号从该表中删除。也就是说,该表记录: x86所有全局符号-被本地库重定位的符号 • X86重定位表:记录所有x86库文件对本地符号的使用,这些符号需要本地库中定义的符号去重定位 • 符号处理模块:该模块对遍历到的每个x86符号进行解析,判断应该用x86符号重定位loongson本地符号,还是用loongson本地符号去重定位x86相应符号 • 重定位:本文中提到的重定位符号,都是指对需要重定位的符号进行重定位,这是具体实现中的一个细节

  10. 相关模块 • 库包装相关功能 • 在被包装的x86本地库装载时,其相应的本地库不会被装载,只有在用到的时候才会被装载,也就是说在x86 loader链接装载x86相关文件时,不会有loongson本地库被装载 • 我们不妨把x86 load过程作为一个整体,本模块所有工作都是在该模块之后进行。 • 模块调用点 • X86loader 刚结束时 • X86 loader结束之后每次dlopen装载x86文件(需要自己截获x86 dlopen) • X86 loader结束之后dbt每次dlopen打开包装库 X86 loader X86 dlopen Dbt dlopen 调用点

  11. 调用点-X86 loader结束 • 实现步骤 • 在x86loader结束之后,根据x86装载序遍历x86主文件和共享目标文件的符号表,记录符号信息,形成x86全局符号表 • 调用符号处理模块

  12. 符号处理模块 • 对x86全局符号表的每一个符号,使用dlopen\dlsym上述功能来查找,如果该符号不为空 • 如果该符号在被包装的库里, • 则用该符号值去重定位所有当前及以后装载的x86库文件中的该符号(x86主程序中的符号不需重定位) • 并将该符号从x86全局符号表中删除 • 如果该符号不在被包装的库里,说明不是插件依赖的本地库,不需要处理。 • 如果该符号不存在,说明现在已装载的本地库中没有定义该符号 • 如果x86符号值不为0,则用该x86符号的值去重定位所有在此之后装载的被包装的本地库 • 如果为0,则将该符号添加到x86重定位表中,并在以后装载的本地包装库中搜索符号来重定位 该处以及x86dlopen调用点处理 本地dlopen调用点处理

  13. 调用点-x86 dlopen装载文件 • 每当x86文件被dlopen装载,检查其flag是否包含RTLD_GLOBAL,如果有,将其符号信息添加到x86全局符号表,并将为0的符号添加到x86重定位表。 • 对该x86库中每一个需要重定位的符号,判断x86全局符号表中是否存在该符号 • 如果有,应该用x86中符号值来重定位该符号,则x86 loader会进行定位,不予处理; • 否则,调用dlopen\dlsym查找本地是否装载了该符号, • 如果装载了并且在包装库中,则用本地值来重定位该x86符号,并将该符号从x86全局符号表中删除。 • 否则,会用该值去重定位本地库,这在本地库被dlopen时会检测, 这里不需处理。

  14. 实现-本地dlopen打开包装库 • Dbt 库包装模块使用dlopen(设flag含RTLD_GLOBAL)打开包装的本地库时, • 对本地库中每一个需要重定位的符号 • 如果x86全局符号表存在并且不为0,则用x86符号值来重定位该符号值 • 如果x86全局符号表中不存在该值,那应该用本地库中的符号定位该值,本地loader会帮助处理,我们不予处理。 • 对x86重定位表的每一个符号,使用dlsym检查该库中有没有这个符号定义, • 如果有,则用本地符号值来重定位该值,并将该符号从x86重定位表删除 • 如果没有,还会在以后装载本地库时搜索,现在不需处理。

  15. 总结

More Related