商业程序如何加载自己的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 qtcreator
Dynamic 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变量代表了此目录。关于ORIGIN变量代表了此目录。关于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 -lfoo
lib/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拷贝到其他目录试试。发现程序也可以正常运行。