Linux中用绝对路径调用C程序,Linux C编程(8) 使用相对路径加载动态库

商业程序如何加载自己的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

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拷贝到其他目录试试。发现程序也可以正常运行。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值