linux下linux 找不到共享库库有没有模块入口

下次自动登录
现在的位置:
& 综合 & 正文
linux下把共享库(SO)加载到指定的内存地址
一位朋友最近遇到一个棘手的问题,希望把共享库(SO)加载到指定的内存地址,目的可能是想通过prelink来加快应用的起动速度。他问我有没有什么方法。我知道Windows下是可以的,比如在VC6里设置/base的值就行了,所以相信在linux下也是可行的。
VC有编译选项可以设置,猜想gcc也应该有吧。gcc本身只是一个外壳,链接工作是由于ld完成的,当然是应该去阅读ld命令行选项文档。很快发现ld有个—image-base选项,可以设置动态库的加载地址。
通过Xlinker把这个参数传递给ld,但是ld不能识别这个选项:
gcc -g -shared test.c -Xlinker --image-base -Xlinker 0x00c00000 -o libtest.so
/usr/bin/ld: unrecognized option '--image-base'
/usr/bin/ld: use the --help option for usage information
collect2: ld returned 1 exit statu
再仔细看手册,原来这个选项只适用于PE文件,PE文件是Windows下专用的,在linux下自然用不了,看来得另想办法。
我知道ld script可以控制ld的行为,于是研究ld script的写法,按照手册里的说明,写了一个简单的ld script:
. = 0x00c00000;
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
按下列方式编译:
gcc -shared -g -Xlinker --script -Xlinker ld.s test.c -o libtest.so
gcc -g main.c -L./ -ltest -o test.exe
用ldd查看,加载地址正确。
[root@localhost lds]# ldd test.exe
linux-gate.so.1 =& (0x00aff000)
libtest.so =& ./libtest.so (0x00c00000)
libc.so.6 =& /lib/libc.so.6 (0x007fa000)
/lib/ld-linux.so.2 (0x007dd000)
但运行时会crash:
[root@localhost lds]# ./test.exe
Segmentation fault
调试运行可以发现:
Starting program: /work/test/lds/test.exe
Reading symbols from shared object read from target memory...done.
Loaded system supplied DSO at 0x452000
Program received signal SIGSEGV, Segmentation fault.
0x007e7a10 in _dl_relocate_object () from /lib/ld-linux.so.2
#0 0x007e7a10 in _dl_relocate_object () from /lib/ld-linux.so.2
#1 0x007e0833 in dl_main () from /lib/ld-linux.so.2
#2 0x007f056b in _dl_sysdep_start () from /lib/ld-linux.so.2
#3 0x007df48f in _dl_start () from /lib/ld-linux.so.2
#4 0x007dd847 in _start () from /lib/ld-linux.so.2
猜想可能是ld.s写得不全,导致一些信息不正确。于是用ld –verbose导出一个默认的ld script。不出所料,默认的ld script非常冗长,下面是开头一段:
/* Script for -z combreloc: combine and sort reloc sections */
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
"elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SEARCH_DIR("/usr/i386-redhat-linux/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = 0x); . = 0x + SIZEOF_HEADERS;
: { *(.interp) }
: { *(.hash) }
: { *(.dynsym) }
: { *(.dynstr) }
.gnu.version
: { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
按照ld script的语法,我把它修改为(红色部分为新增行):
/* Script for -z combreloc: combine and sort reloc sections */
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
"elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SEARCH_DIR("/usr/i386-redhat-linux/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = 0x); . = 0x + SIZEOF_HEADERS;
. = 0x00c00000;
: { *(.interp) }
: { *(.hash) }
: { *(.dynsym) }
: { *(.dynstr) }
.gnu.version
: { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
用这个ld script再次测试,一切正常。又验证多个共享库的情况,也正常,下面是测试数据:
int test(intn)
inttest1(intn)
externinttest(intn);
externinttest1(intn);
#include &stdio.h&
intmain(intargc, char* argv[])
printf("Hello: %d %d/n", test(100), test1(200));
getchar();
gcc -shared -g -Xlinker --script -Xlinker ld.s test.c -o libtest.so
gcc -shared -g -Xlinker --script -Xlinker ld1.s test1.c -o libtest1.so
gcc -g main.c -L./ -ltest -ltest1 -o test.exe
rm -f *.so *.exe
libtest.so的加载地址为:0x00c00000
libtest1.so的加载地址为:0x00d00000
ldd显示结果:
linux-gate.so.1 =& (0x00aa3000)
libtest.so =& ./libtest.so (0x00c00000)
libtest1.so =& ./libtest1.so (0x00d00000)
libc.so.6 =& /lib/libc.so.6 (0x007fa000)
/lib/ld-linux.so.2 (0x007dd000)
maps的内容为:
007dd000-007f6000 r-xp :01 521466
/lib/ld-2.4.so
007f0 r-xp :01 521466
/lib/ld-2.4.so
007f0 rwxp :01 521466
/lib/ld-2.4.so
007fa000- r-xp :01 523579
/lib/libc-2.4.so
29000 r-xp :01 523579
/lib/libc-2.4.so
2a000 rwxp :01 523579
/lib/libc-2.4.so
2d000 rwxp :00 0
00c00 r-xp :03 16370
/work/test/ldsex/libtest.so
00c00 rwxp :03 16370
/work/test/ldsex/libtest.so
00cf00 r-xp 00cf 0
00d00 r-xp :03 16373
/work/test/ldsex/libtest1.so
00d00 rwxp :03 16373
/work/test/ldsex/libtest1.so
49000 r-xp :03 16374
/work/test/ldsex/test.exe
4a000 rw-p :03 16374
/work/test/ldsex/test.exe
b7fdf000-b7fe0000 rw-p b7fdf000 00:00 0
b7fed000-b7ff0000 rw-p b7fed000 00:00 0
bf8db000-bf8f0000 rw-p bf8db000 00:00 0
从以上测试结果可以看出,这种方法是可行的。
&&&&推荐文章:
【上篇】【下篇】在编译共享库必须加上-fpic。这是为什么呢?
首先看一个简单的例子:
#include &stdio.h&
int fun1()
printf("fun1\n");
先不加-fpic的情况下生成库,反汇编查看fun1的机器码
0000044c &fun1&:
$0x18,%esp
c7 04 24 b2 04 00 00
$0x4b2,(%esp)
e8 fc ff ff ff
45a &fun1+0xe&
可以看出调用printf的位置是那个唯一的一个call,并不是跳转到plt表,有关plt表的内容可以查看我前面的博文。也就是说在该库被加载时需要修改代码段来达到重定位的效果。那么每一个加载这个共享库的程序都要有这个库的一份拷贝,这样实际上就没有达到共享库的效果。
看下运行时的机器码
0xb771d44c &+0&:
0xb771d44d &+1&:
0xb771d44f &+3&:
$0x18,%esp
0xb771d452 &+6&:
c7 04 24 b2 d4 71 b7
$0xb771d4b2,(%esp)
0xb771d459 &+13&:
e8 42 b2 ea ff
0xb75c86a0 &puts&
0xb771d45e &+18&:
0xb771d45f &+19&:
显然代码段被修改了。
再看一下再加了-fpic的情况下生成的库,反汇编看下fun1的机器码
0000045c &fun1&:
$0x14,%esp
e8 ef ff ff ff
457 &__i686.get_pc_thunk.bx&
81 c3 8c 1b 00 00
$0x1b8c,%ebx
8d 83 ee e4 ff ff
-0x1b12(%ebx),%eax
%eax,(%esp)
e8 04 ff ff ff
380 &puts@plt&
$0x14,%esp
看过很多汇编代码的人知道printf有时候是puts,所以这段机器码中printf就对应第二个call,也就是跳转到plt表中去查找puts符号,那么这样就达到了共享库的效果,此时每一个需要该库的程序只是有一个plt表的拷贝,而代码段所有应用程序是共享的。
再看下运行时机器码
0xb773045c &+0&:
0xb773045d &+1&:
0xb773045f &+3&:
0xb7730460 &+4&:
$0x14,%esp
0xb7730463 &+7&:
e8 ef ff ff ff
0xb7730457 &__i686.get_pc_thunk.bx&
0xb7730468 &+12&:
81 c3 8c 1b 00 00
$0x1b8c,%ebx
0xb773046e &+18&:
8d 83 ee e4 ff ff
-0x1b12(%ebx),%eax
0xb7730474 &+24&:
%eax,(%esp)
0xb7730477 &+27&:
e8 04 ff ff ff
0xb7730380 &puts@plt&
0xb773047c &+32&:
$0x14,%esp
0xb773047f &+35&:
0xb7730480 &+36&:
0xb7730481 &+37&:
显然是一致的。
所以,在编译共享库时是必须加上-fpic的选项的,否则共享库省下的仅仅是硬盘上的空间,而没有省下内存。
阅读(...) 评论()拒绝访问 | www. | 百度云加速
请打开cookies.
此网站 (www.) 的管理员禁止了您的访问。原因是您的访问包含了非浏览器特征(f043bf-ua98).
重新安装浏览器,或使用别的浏览器关于Ubuntu添加共享库路径_Linux教程_Linux公社-Linux系统门户网站
你好,游客
关于Ubuntu添加共享库路径
来源:Linux社区&
作者:ever__love
关于添加共享库路径:
1. 将绝对路径写入 /etc/ld.so.conf
2. ldconfig
*****************************
下面是繁琐的解释,愿意看的就看下。。。。。
库文件在连接(静态库和共享库)和运行(仅限于使用共享库的程序)时被使用,其搜索路径是在系统中进行设置的。一般 Linux 系统把 /lib 和 /usr/lib 两个目录作为默认的库搜索路径,所以使用这两个目录中的库时不需要进行设置搜索路径即可直接使用。对于处于默认库搜索路径之外的库,需要将库的位置添加到 库的搜索路径之中。设置库文件的搜索路径有下列两种方式,可任选其一使用:
  在环境变量 LD_LIBRARY_PATH 中指明库的搜索路径。
  在 /etc/ld.so.conf 文件中添加库的搜索路径。
  将自己可能存放库文件的路径都加入到/etc/ld.so.conf中是明智的选择
  添加方法也极其简单,将库文件的绝对路径直接写进去就OK了,一行一个。例如:
  /usr/X11R6/lib
  /usr/local/lib
  /opt/lib
  需要注意的是:第二种搜索路径的设置方式对于程序连接时的库(包括共享库和静态库)的定位已经足够了,但是对于使用了共享库的程序的执行还是不 够的。这是因为为了加快程序执行时对共享库的定位速度,避免使用搜索路径查找共享库的低效率,所以是直接读取库列表文件 /etc/ld.so.cache 从中进行搜索的。/etc/ld.so.cache 是一个非文本的数据文件,不能直接编辑,它是根据 /etc/ld.so.conf 中设置的搜索路径由 /sbin/ldconfig 命令将这些搜索路径下的共享库文件集中在一起而生成的(ldconfig 命令要以 root 权限执行)。因此,为了保证程序执行时对库的定位,在 /etc/ld.so.conf 中进行了库搜索路径的设置之后,还必须要运行 /sbin/ldconfig 命令更新 /etc/ld.so.cache 文件之后才可以。ldconfig ,简单的说,它的作用就是将/etc/ld.so.conf列出的路径下的库文件缓存到/etc/ld.so.cache 以供使用。因此当安装完一些库文件,(例如刚安装好glib),或者修改ld.so.conf增加新的库路径后,需要运行一下 /sbin/ldconfig使所有的库文件都被缓存到ld.so.cache中,如果没做,即使库文件明明就在/usr/lib下的,也是不会被使用 的,结果编译过程中抱错,缺少xxx库,去查看发现明明就在那放着,搞的想大骂computer蠢猪一个。
  在程序连接时,对于库文件(静态库和共享库)的搜索路径,除了上面的设置方式之外,还可以通过 -L 参数显式指定。因为用 -L 设置的路径将被优先搜索,所以在连接的时候通常都会以这种方式直接指定要连接的库的路径。
  前面已经说明过了,库搜索路径的设置有两种方式:在环境变量 LD_LIBRARY_PATH 中设置以及在 /etc/ld.so.conf 文件中设置。其中,第二种设置方式需要 root 权限,以改变 /etc/ld.so.conf 文件并执行 /sbin/ldconfig 命令。而且,当系统重新启动后,所有的基于 GTK2 的程序在运行时都将使用新安装的 GTK 库。不幸的是,由于 GTK 版本的改变,这有时会给应用程序带来兼容性的问题,造成某些程序运行不正常。为了避免出现上面的这些情况,在 GTK 及其依赖库的安装过程中对于库的搜索路径的设置将采用第一种方式进行。这种设置方式不需要 root 权限,设置也简单:
  $ export LD_LIBRARY_PATH=/opt/gtk/lib:$LD_LIBRARY_PATH
  可以用下面的命令查看 LD_LIBRAY_PATH 的设置内容:
  $ echo $LD_LIBRARY_PATH
  至此,库的两种设置就完成了。
相关资讯 & & &
& (10/14/:49)
& (07/08/:10)
& (10/31/:01)
& (10/14/:00)
& (02/15/:58)
& (10/11/:23)
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款}

我要回帖

更多关于 linux 找不到共享库 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信