商业程序如何加载自己的so
使用LD_LIBRARY_PATH的缺点是要实现设置LD_LIBRARY_PATH。不够自动化。那么大型的商业程序是如何加载自己的so呢。
这里以QtCreator为例。
QtCreator安装在/home/xxx/Qt5.3.1目录下。使用ldd查看qtcreator依赖的so。结果如下:
xxx@ubuntu:~/Qt5.3.1/Tools/QtCreator/bin$ ldd qtcreator linux-gate.so.1 => (0xb7701000) libExtensionSystem.so.1 => /home/xxx/Qt5.3.1/Tools/QtCreator/bin/./../lib/qtcreator/libExtensionSystem.so.1 (0xb76c2000) libQt5Widgets.so.5 => /home/xxx/Qt5.3.1/Tools/QtCreator/bin/./../lib/qtcreator/libQt5Widgets.so.5 (0xb707e000) libQt5Network.so.5 => /home/xxx/Qt5.3.1/Tools/QtCreator/bin/./../lib/qtcreator/libQt5Network.so.5 (0xb6f19000) libQt5Gui.so.5 => /home/xxx/Qt5.3.1/Tools/QtCreator/bin/./../lib/qtcreator/libQt5Gui.so.5 (0xb69d8000) libQt5Core.so.5 => /home/xxx/Qt5.3.1/Tools/QtCreator/bin/./../lib/qtcreator/libQt5Core.so.5 (0xb649d000) libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb646b000) libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0xb6382000) libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xb6364000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb61b6000) libgobject-2.0.so.0 => /usr/lib/i386-linux-gnu/libgobject-2.0.so.0 (0xb6164000) libglib-2.0.so.0 => /lib/i386-linux-gnu/libglib-2.0.so.0 (0xb6058000) libX11.so.6 => /usr/lib/i386-linux-gnu/libX11.so.6 (0xb5f24000) libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb5edd000) libGL.so.1 => /usr/lib/i386-linux-gnu/mesa/libGL.so.1 (0xb5e7d000) libicui18n.so.52 => /home/xx/Qt5.3.1/Tools/QtCreator/bin/./../lib/qtcreator/./libicui18n.so.52 (0xb5c53000) libicuuc.so.52 => /home/xxx/Qt5.3.1/Tools/QtCreator/bin/./../lib/qtcreator/./libicuuc.so.52 (0xb5ad7000) libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xb5ad2000) libgthread-2.0.so.0 => /usr/lib/i386-linux-gnu/libgthread-2.0.so.0 (0xb5ace000) librt.so.1 => /lib/i386-linux-gnu/librt.so.1 (0xb5ac5000) /lib/ld-linux.so.2 (0xb7702000) libffi.so.6 => /usr/lib/i386-linux-gnu/libffi.so.6 (0xb5abe000) libpcre.so.3 => /lib/i386-linux-gnu/libpcre.so.3 (0xb5a80000) libxcb.so.1 => /usr/lib/i386-linux-gnu/libxcb.so.1 (0xb5a5e000) libglapi.so.0 => /usr/lib/i386-linux-gnu/libglapi.so.0 (0xb5a45000) libXext.so.6 => /usr/lib/i386-linux-gnu/libXext.so.6 (0xb5a32000) libXdamage.so.1 => /usr/lib/i386-linux-gnu/libXdamage.so.1 (0xb5a2e000) libXfixes.so.3 => /usr/lib/i386-linux-gnu/libXfixes.so.3 (0xb5a28000) libX11-xcb.so.1 => /usr/lib/i386-linux-gnu/libX11-xcb.so.1 (0xb5a25000) libxcb-glx.so.0 => /usr/lib/i386-linux-gnu/libxcb-glx.so.0 (0xb5a0c000) libxcb-dri2.so.0 => /usr/lib/i386-linux-gnu/libxcb-dri2.so.0 (0xb5a06000) libxcb-dri3.so.0 => /usr/lib/i386-linux-gnu/libxcb-dri3.so.0 (0xb5a02000) libxcb-present.so.0 => /usr/lib/i386-linux-gnu/libxcb-present.so.0 (0xb59fe000) libxcb-sync.so.1 => /usr/lib/i386-linux-gnu/libxcb-sync.so.1 (0xb59f7000) libxshmfence.so.1 => /usr/lib/i386-linux-gnu/libxshmfence.so.1 (0xb59f3000) libXxf86vm.so.1 => /usr/lib/i386-linux-gnu/libXxf86vm.so.1 (0xb59ed000) libdrm.so.2 => /usr/lib/i386-linux-gnu/libdrm.so.2 (0xb59df000) libicudata.so.52 => /home/xxx/Qt5.3.1/Tools/QtCreator/bin/./../lib/qtcreator/././libicudata.so.52 (0xb4373000) libXau.so.6 => /usr/lib/i386-linux-gnu/libXau.so.6 (0xb436e000) libXdmcp.so.6 => /usr/lib/i386-linux-gnu/libXdmcp.so.6 (0xb4367000)
在看一下本身直接加载的动态库:
xxx@ubuntu:~/Qt5.3.1/Tools/QtCreator/bin$ readelf --dynamic qtcreatorDynamic section at offset 0x11eb0 contains 30 entries: 标记 类型 名称/值 0x00000001 (NEEDED) 共享库:[libExtensionSystem.so.1] 0x00000001 (NEEDED) 共享库:[libQt5Widgets.so.5] 0x00000001 (NEEDED) 共享库:[libQt5Network.so.5] 0x00000001 (NEEDED) 共享库:[libQt5Gui.so.5] 0x00000001 (NEEDED) 共享库:[libQt5Core.so.5] 0x00000001 (NEEDED) 共享库:[libpthread.so.0] 0x00000001 (NEEDED) 共享库:[libstdc++.so.6] 0x00000001 (NEEDED) 共享库:[libgcc_s.so.1] 0x00000001 (NEEDED) 共享库:[libc.so.6] 0x0000000f (RPATH) Library rpath: [$ORIGIN/../lib/qtcreator]
秘密就在这句:0x0000000f (RPATH) Library rpath: [$ORIGIN/../lib/qtcreator]
rpath与ORIGIN
rpath是gcc的一个参数。rpath添加一个目录。当程序被加载时,搜寻此目录,寻找动态库。rpath添加的目录信息保存在可执行文件中。即使这句
0x0000000f (RPATH) Library rpath: [xxx]。
现在的问题是,可执行文件如何知道自身所在目录。
ORIGIN更详细的信息,可参考此文档。
例子
例子目录结构如下
src
…main.c
…Makefile
…lib/foo.c
操作系统:ubuntu 14 32位
编译i:gcc 4.8
main.c文件源码
void test_tk();int main(void){ test_tk(); return 0;}
Makefile文件内容
main:main.c lib/libfoo.so gcc -L${shell pwd}/lib -g -Wall -o test -Wl,-rpath,'$$ORIGIN/lib' main.c -lfoolib/libfoo.so:lib/foo.c gcc -g -Wall -fPIC -shared -o lib/libfoo.so lib/foo.c
foo.c文件源码
#include <stdio.h>void test_tk(){ printf("called!\n");}
编译,生成test可执行文件。
执行readelf –dynamic test 来看加载的动态库。
Dynamic section at offset 0xf04 contains 26 entries: 标记 类型 名称/值 0x00000001 (NEEDED) 共享库:[libfoo.so] 0x00000001 (NEEDED) 共享库:[libc.so.6] 0x0000000f (RPATH) Library rpath: [$ORIGIN/lib] ..........................................................
运行test。执行结果位
called!
可以讲src拷贝到其他目录试试。发现程序也可以正常运行。
联系客服