动态连接库和符号symbol.docx
- 文档编号:28906347
- 上传时间:2023-07-20
- 格式:DOCX
- 页数:9
- 大小:19.47KB
动态连接库和符号symbol.docx
《动态连接库和符号symbol.docx》由会员分享,可在线阅读,更多相关《动态连接库和符号symbol.docx(9页珍藏版)》请在冰豆网上搜索。
动态连接库和符号symbol
动态连接库和符号(symbol)
sharedlibrary(.so)
"ProgramLibraryHowto-SharedLibraries"是很好的材料,下面的内容多是据此整理的.
定义:
Sharedlibrariesarelibrariesthatareloadedbyprogramswhentheystart.
使用sharedlibrary(共享库)会有很多好处,比如软件升级,不难想象.
命名约定:
1.soname:
每个共享库都有一个soname,形式为"libNAME.so.x",其中x是版本号.如"libc.so.6".
2.realname:
真正的库文件,一般形式为"soname.y[.z]",即"libName.so.x.y[.z]",其中y是minornumber,z是releasenumber,是可选的.如"libattr.so.1.1.0".
3.linkername:
compiler用来请求库时使用的名字,一般是没有版本号的soname.
放置位置&load/preload:
共享库一般放在一些约定的目录下,如/usr/lib/,/usr/local/lib,/lib/等.这其实是遵循FHS的,比如/usr/local/lib下放置的一般是用户开发的库.
在启动程序时,programloader(ld-linux.so.x)会找到并加载程序需要的共享库,loader查找的路径一般就是上述的几个目录,这些目录在/etc/ld.so.conf文件中配置.
如果只想覆盖共享库的某几个函数,保持其余函数不变,则可以将共享库名字和函数名字输入到/etc/ld.so.preload中,这里面定义的规则会覆盖标准规则.
cachearrangement&ldconfig
实际上,在启动程序时再去搜寻所需的共享库不是高效做法,所以loader使用了cache.ldconfig的作用就是读取文件/etc/ld.so.conf,在各个库目录中,对共享库设置合适的symboliclink(使得遵守命名约定),然后写入某种数据到/etc/ld.so.cache,这个文件再今后就被其他程序使用,从而大幅提升了共享库的查找速度.
所以在每加入/移除一个共享库,或者修改了/etc/ld.so.conf(即修改库目录)的时候,最要运行ldconfig.
创建共享库
step1.编译出objectfiles,需要使用-fPIC或-fpicflag.fPIC和fpic的区别是,前者生成的文件更大,不过具有更好的平台无关性,后者恰好相反.这说明前者为了platform-independence做了更多工作.
step2.用-Wl向linker传递参数.如:
"gcc-shared-Wl,-soname,libmystuff.so.1-olibmystuff.so.1.0.1a.ob.o-lc".
step3.把共享库拷贝到约定的某个目录下即可,如/usr/local/lib.
step4.ldconfig-n/path/to/lib.
elf
elf的内容参考"elf&libelf,elftoolchain",它是一种格式,也是一种规范,可以用libelf写程序去操作它,可以用objdump、nm和readelf去读取elf文件的内容.
symbols
我也已经熟悉共享库了,我知道ldconfig的作用,我知道常用的库放置目录,我知道ltrace,ldd可以用来帮助确认某程序和某些共享库的关联关系是否正确.
所以,如果没有symbols这一节,本篇文章存在的意义不大.
"InsideELFSymbolTables"是绝佳的资料,当然正如很多网文一样,它仅是帮助理解,而不涉及很深的细节.细节标准什么的还是要看书和文档了,这方面很不错的书籍就是校友的<程序员的自我修养>了.
查看elf规范,你必然可以看到symtab和dynsym,如"ELF-64ObjectFileFormat"中"4.Sections"就列出了标准的sections,.symtab和.dynsym就是其中之二.
实际上,我们知道机器可执行的是machinecode,而我们使用的高级语言编程,并不是利用晦涩的机器码,而是用human-readable的变量名,函数名等,这些名字就是symbolicname.编译器在编译时收集symbol信息,并储存在objectfile的.symtab和.dynsym中.symbols是linker和debugger所必需的信息,如果没有symbols,试想debugger如何能展示给用户调试信息了?
如果没有symbol,而只有地址(相对于objectfile的offset),linker如何能够链接多个objectfile了?
对于linker和symbol,我们可以做个小实验:
//编写一个简单的a.c
$cata.c
voidfunc(void)
{
printf("callfunc()\n");
}
$nma.o
00000000Tfunc
Uputs
//编写一个简单的main.c
$catmain.c
#include<stdio.h>
externvoidfunc(void);
intmain(
{
func();
return0;
}
$nmmain.o
Ufunc
00000000Tmain
//正常情况下
$gccmain.oa.o-omain
$./main
callfunc()
//为了验证symbol对于linker来说是必需品,我做如下操作
$filea.o
a.o:
ELF32-bitLSBrelocatable,Intel80386,version1(SYSV),notstripped
$stripa.o
$filea.o
a.o:
ELF32-bitLSBrelocatable,Intel80386,version1(SYSV),stripped
$gccmain.oa.o-omain
main.o:
Infunction`main':
/home/xan/lab/main.c:
7:
undefinedreferenceto`func'
collect2:
ldreturned1exitstatus
这个小实验证实了symbols对于linker的重要性,同时使用file看出"notstripped"->"stripped"的变化,说的就是去除了symbols信息.
现在假使我们生成了最后的可执行文件(当然是elf格式了),那么这个elf中是否包含symbols呢?
其中又是否需要symbols呢?
不妨先下结论:
一般地,生成的可执行文件都是包含symbols,不过这些信息不是程序执行所必需的,可以通过strip(Discardsymbolsfromobjectfiles)去除.
同样可以做个小实验:
//仍用上面实验的代码
$filemain
main:
ELF32-bitLSBexecutable,Intel80386,version1(SYSV),dynamicallylinked(usessharedlibs),forGNU/Linux2.6.18,notstripped
$./main
callfunc()
$stripmain
$filemain
main:
ELF32-bitLSBexecutable,Intel80386,version1(SYSV),dynamicallylinked(usessharedlibs),forGNU/Linux2.6.18,stripped
$./main
callfunc()
$
这个小实验证实了symbols对于可执行文件来说不是必需的,这是因为可执行的代码都是machinecode,只需要address信息,无需symbol信息.
对于elf和symbols,还是好理解的啦.就是我elf文件中留了一席之地给你放symbols,compiler在生成elf时会往其中填充.debugger/nm/readelf等可以来读取.不过这些symbols不是程序执行必需的,所以完全可以去除,只不过去除之后,debugger就读不到信息了.
而对于共享库来说,情况略复杂些了.我们来特别说明.
共享库和symbols
在继续下去之前,先来看两个事实.
$ldd/bin/ls
linux-gate.so.1=>(0xb7711000)
libselinux.so.1=>/lib/libselinux.so.1(0xb76e5000)
librt.so.1=>/lib/i686/cmov/librt.so.1(0xb76dc000)
libacl.so.1=>/lib/libacl.so.1(0xb76d4000)
libc.so.6=>/lib/i686/cmov/libc.so.6(0xb758d000)
libdl.so.2=>/lib/i686/cmov/libdl.so.2(0xb7589000)
/lib/ld-linux.so.2(0xb7712000)
libpthread.so.0=>/lib/i686/cmov/libpthread.so.0(0xb7570000)
libattr.so.1=>/lib/libattr.so.1(0xb756b000)
$nm/lib/i686/cmov/libc.so.6
nm:
/lib/i686/cmov/libc.so.6:
nosymbols-->libattr,libacl也一样,都显示"nosymbols"
//而libpthread有一大串
$nm/lib/i686/cmov/libpthread.so.0|tail
Utwalk@@GLIBC_2.0
Uuname@@GLIBC_2.0
Uunlink@@GLIBC_2.0
0000c930tunwind_cleanup
0000c970tunwind_stop
0000cfd0Wvfork
0000de90Wwait
0000df50Wwaitpid
0000c140twalker
0000d020Wwrite
这仅仅是因为有些库做了strip,而其他库没做strip而已?
还是说对于某些共享库来说,symbols也是必需的?
目前不知答案,分析下去.
前面提到.symtab和.dynsym两个不同的symboltable,它们有什么区别?
.dynsym是.symtab的一个子集,大家都有疑问,为什么要两个信息重合的结构?
需要先了解allocable/non-allocableELFsection,ELF文件包含一些sections(如code和data)是在运行时需要的,这些sections被称为allocable;而其他一些sections仅仅是linker,debugger等工具需要,在运行时并不需要,这些sections被称为non-allocable的.当linker构建ELF文件时,它把allocable的数据放到一个地方,将non-allocable的数据放到其他地方.当OS加载ELF文件时,仅仅allocable的数据被映射到内存,non-allocable的数据仍静静地呆在文件里不被处理.strip就是用来移除某些non-allocablesections的.
.symtab包含大量linker,debugger需要的数据,但并不为runtime必需,它是non-allocable的;.dynsym包含.symtab的一个子集,比如共享库所需要在runtime加载的函数对应的symbols,它世allocable的.
因此,得到答案:
1.strip移除的应是.symtab.
2.nm读取的应是.symtab:
上面发现的libattr等nm结果为空,libpthreadnm结果非空应是正常的.
3.共享库包含的.dynsym是runtime必需的,是allocable的.
可做验证,期望的结果为:
1.striplibpthread,ls依然能够工作.
2.striplibpthread,nmlibpthread得到结果为空.
3.可以通过设置nmoptions,或使用readelf读出.dynsym的内容.
$sudostrip/lib/i686/cmov/libpthread-2.11.3.so
$file/lib/i686/cmov/libpthread-2.11.3.so
/lib/i686/cmov/libpthread-2.11.3.so:
ELF32-bitLSBsharedobject,Intel80386,version1(SYSV),dynamicallylinked(usessharedlibs),forGNU/Linux2.6.18,stripped
$ls
...(输出正确结果)
$nm/lib/i686/cmov/libpthread-2.11.3.so
nm:
/lib/i686/cmov/libpthread-2.11.3.so:
nosymbols
$readelf-s/lib/i686/cmov/libpthread-2.11.3.so|tail
322:
0000b6a0292FUNCGLOBALDEFAULT13__pthread_clock_gettime@@GLIBC_PRIVATE
323:
0000ec3046FUNCGLOBALDEFAULT13pthread_mutex_consistent_@@GLIBC_2.4
324:
0000b3a050FUNCGLOBALDEFAULT13pthread_testcancel@@GLIBC_2.0
325:
0000d6b0111FUNCWEAKDEFAULT13fsync@@GLIBC_2.0
326:
0000d1f0180FUNCWEAKDEFAULT13fcntl@@GLIBC_2.0
327:
0000dde0176FUNCWEAKDEFAULT13tcdrain@@GLIBC_2.0
328:
000093907FUNCGLOBALDEFAULT13pthread_mutexattr_destroy@@GLIBC_2.0
329:
00006de023FUNCGLOBALDEFAULT13pthread_yield@@GLIBC_2.2
330:
000077c0259FUNCGLOBALDEFAULT13pthread_mutex_init@@GLIBC_2.0
331:
000093c049FUNCGLOBALDEFAULT13pthread_mutexattr_setpsha@@GLIBC_2.2
$readelf-s/lib/libattr.so.1.1.0|tail
48:
00002f5050FUNCGLOBALDEFAULT13lremovexattr@@ATTR_1.0
49:
0000301057FUNCGLOBALDEFAULT13llistxattr@@ATTR_1.0
50:
00002ae050FUNCGLOBALDEFAULT13attr_copy_check_permissio@@ATTR_1.1
51:
00001b50259FUNCGLOBALDEFAULT13attr_set@@ATTR_1.0
52:
00002b201002FUNCGLOBALDEFAULT13attr_copy_action
53:
000031f071FUNCGLOBALDEFAULT13setxattr@@ATTR_1.0
54:
00001380543FUNCGLOBALDEFAULT13attr_list@@ATTR_1.2
55:
000030d064FUNCGLOBALDEFAULT13lgetxattr@@ATTR_1.0
56:
00002fd057FUNCGLOBALDEFAULT13flistxattr@@ATTR_1.0
57:
00002f1050FUNCGLOBALDEFAULT13fremovexattr@@ATTR_1.0
至此,对symbols和共享库,ELF的关系的了解告一段落.
more
既然已经说到共享库(sharedlibrary),不妨稍微提一下动态装载库(DynamicallyLoadedLibraries),共享库是在程序startup时被加载,而DLL(注意区别于windows下的概念)则是在程序运行过程中显式被加载,实际上就是调用dlopen,dlsym等接口显式地打开共享库,显示地查找库中的symbol,然后找到对应的代码去执行.
HowToWriteSharedLibrariesbyUlrichDrepper.
--EOF--
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 动态 连接 符号 symbol
