免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4150 | 回复: 17
打印 上一主题 下一主题

关于静态库和动态库的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-08 22:34 |只看该作者 |倒序浏览
现有一静态库(libdep.a),定义如下函数:

void func(void)
{
   
staticint inited =0;
   
if(!inited)
   {
     do_init();
     inited
=1;
   }
}


有两个动态库,分别命名为libref1.so 和 libref2.so,这两个动态库中分别调用了静态库libdep.a中的func函数. 动态库在编译的时候链接了静态库libdep.a。
  
libref1.so中

void ref1_func(void)
{
   func();
}



libref2.so中

void ref2_func(void)
{
    func();
}



应用程序main函数中又调用动态库中的这两个函数:

int main(int argc,char**argv)
{
   ref1_func();
   ref2_func();
   
return0;
}


程序运行发现 do_init()只被执行了一次。
  
但是如果在应用程序用,使用dlopen/dlsym来加载动态库

int main(int argc,char**argv)
{
   
void* handle1,*handle2;
   
void (*ref1_func)(void);
   
void (*ref2_func)(void);
   handle1
= dlopen("libref1.so",RTLD_LAZY);
   ref1_func
= dlsym(handle1,"ref1_func");
   handle2
= dlopen("libref2.so",RTLD_LAZY);
   ref2_func
= dlsym(handle2,"ref2_func");
  
   ref1_func();
   ref2_func();

   dlclose(handle1);

   dlclose(handle2);

   return0;
}


程序运行发现do_init()被执行了两次。
  

问题1:两个动态库中属于静态库(libdep.a)的部分被合并了吗?

(也就是如果一个静态库被链接到100个动态库中,而一个进程运行时加载了这些动态库,忽略lazy flag,那么进程空间内是有100份静态库的拷贝、还是只有1份呢?我感觉应该是100份。)

问题2:如果确实有两份,静态变量inited共享同一份拷贝吗(否则怎么理解动态链接只运行一次的现象呢)?

(有人说so实际在内存中只装载一次,而各个进程加载它时将代码段部分映射过去,而数据段各个进程各不相同,但是在ELF中静态变量inited作为bss section的一部分同属于data segment啊。难道加载器特别处理bss部分?)

问题3:是不是如同augustusqing所说,“生成的两个so,每个so里面有静态库的拷贝,但记录的符号名字是同名的。当他们直接以-l方式链接进同一个进程的时候,链接和运行过程中,只需要在任何一个so里找到了静态库的符合,程序就开跑,运行的是同一份静态库。所以只执行一次”。也就是说ELF文件不会区分来自不同库的相同符号?


困扰我好几天,多谢了众大侠啦。

[ 本帖最后由 zangkannt 于 2009-4-9 12:51 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2009-04-08 22:43 |只看该作者

回复 #1 zangkannt 的帖子

顶,期待高手解答!

论坛徽章:
0
3 [报告]
发表于 2009-04-08 22:49 |只看该作者

回复 #2 bladmin 的帖子

多谢啊 :wink:

我新来的,好像没有编译器、连接器的专区就放在c/c++了。

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
4 [报告]
发表于 2009-04-08 22:52 |只看该作者
1. 100份
2. 不太可能这种现象,每个动态库都有一份静态函数
3.动态加载比动态链接灵活

论坛徽章:
0
5 [报告]
发表于 2009-04-08 22:59 |只看该作者
《linker and loader》google之。

论坛徽章:
0
6 [报告]
发表于 2009-04-08 23:00 |只看该作者

回复 #4 chenzhanyiczy 的帖子

是啊,既然是100份,也就是两个库各走各的,互不相干,可是问题就出在这里,如何解释只运行一次的问题呢?我在gcc4.3上实验,确实如此。

另:“每个动态库都有一份静态函数” 是不是 “每个动态库都有一份静态变量”?

论坛徽章:
0
7 [报告]
发表于 2009-04-08 23:03 |只看该作者

回复 #5 prolj 的帖子

看了,但是没有说加载器如何特殊处理这种static member,这书上有图就说so的bss还是最终归到整个进程中的bss中。

所以我就认为,加载两个库,各走各的,互不相干。

可是这部问题就出现了。。。

论坛徽章:
0
8 [报告]
发表于 2009-04-08 23:08 |只看该作者
静态库和动态

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
9 [报告]
发表于 2009-04-08 23:11 |只看该作者
问题出在于这个:
staticint inited =0;

func函数变成这样就应该可以的:
void func(void)
{

     do_init();
  
}

论坛徽章:
0
10 [报告]
发表于 2009-04-08 23:18 |只看该作者

回复 #1 zangkannt 的帖子

个人理解:
1,生成的两个so,每个so里面有静态库的拷贝,但记录的符号名字是同名的。当他们直接以-l方式链接进同一个进程的时候,链接和运行过程中,只需要在任何一个so里找到了静态库的符合,程序就开跑,运行的是同一份静态库。所以只执行一次。
2,至于dlsym的方法,则是把so内容mmap到进程空间里,然后dlsym在各自的空间里寻找静态库符号,自然找到的是分开的两份,所以执行两次
3,动态链接和动态加载的区别,就在于链接和加载的区别,就是linker和loader的区别,自然要看《linker&loader》了
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP