我的编程空间,编程开发者的网络收藏夹
学习永远不晚

解决动态库的符号冲突

短信预约 信息系统项目管理师 报名、考试、查分时间动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

解决动态库的符号冲突

解决动态库的符号冲突

一次debug遇到的疑惑某天发现一个程序有点问题,祭上print大法。

图片

一次debug遇到的疑惑

某天发现一个程序有点问题。祭上print大法,在关键的 lib_func() 函数里添加 print 调试信息,重新编译运行。

期望 print 出的信息一点都没有,但是程序确确实实又执行过了 libfunc() ,因为除了添加的调试 print 没有执行,libfunc() 该有的功能都执行了。这真是奇怪了。

程序不会骗人。执行的 libfunc() 肯定不是我们修改后的那个 libfunc() ,一定是别的地方有原版的 lib_func() 被执行了。一番调查,果然如此。为了便于说明,把程序和现象简化说明如下:

程序包含如下代码文件——

main.c # 主程序
plugin.c # 插件程序
lib.c lib.h # 一个库

Makefile如下:

all:main plugin
main:
    cc -o main main.c lib.c -ldl -rdynamic
plugin:
    cc -shared -fPIC -o plugin.so plugin.c lib.c

编译后,生成可执行程序main, 和动态库文件 plugin.so。其中主程序运行的时候,会动态加载插件 plugin.so (调用了 lib.c 里的程序)并执行。

怀疑出问题的地方在lib.c里。修改后的lib.c内容如下,添加了debug字样。

void lib_func() {   
// fprintf(stderr, "%s()
", __func__);
    fprintf(stderr, "debug:%s()
", __func__);
}

因为主程序没问题,就只重新编译了 plugin.so ,重新运行。

期望得到的print的结果是 debug:libfunc() ,实际得到却是 libfunc()

看起来,一个程序里的确有两份 lib_func() 代码。从Makefile可以看出,一份在main程序里,一份在plugin.so里。实际运行的是main里的那份。

事情忽然就有意思了:如果一个程序里包含多个相同的函数,实际执行的是哪一个?

TIPS:可以简单的使用linux的命令 nm <程序文件> 查看程序里有哪些函数

动态库和符号表

尽管程序各不相同,但总有些功能很常见。每个程序都为他们写一遍代码很不划算,于是独立出来成了库,在多个程序之间共享。一个库也可以使用别的库。有两种共享的办法:静态的,动态的。

在编译时,把库的代码复制一份合并到可执行文件里的,是静态库。

在运行时,把库的代码加载一份到内存里的,是动态库。

动态库更节省资源,不用被复制很多次,更新也方便。

负责链接的东西,叫做链接器(linker),负责加载的叫做加载器(loader)。

然而计算机是根据地址来执行的,每条指令执行前都要先确定地址。动态库加载之前,谁都不知道它会被加载到哪里,也就不知道动态库里的指令的地址,只能通过符号(名称)来记录它提供给别人用的函数列表(导出表),以及它期望别人提供给他的函数列表(导入表)。库被加载后,就获得了地址。程序运行前,需要先解析符号表,确定每个符号的实际地址。

我们开头的例子,两个相同名字的 libfunc() ,一个在main程序里,一个在plugin.so里,main先加载,plugin.so使用的 libfunc() 就被解析到了main的 libfunc() 。执行了老的 libfunc() ,而不是我们修改过的带有debug版本。

TIPS:对程序链接和加载有兴趣的同学可以看看 Linkers and Loaders 这本书,非常详细。

和符号有关的编译器选项和环境变量选项

如果条件允许,尽量不要在同一个程序中出现两份代码,出现相同符号的情况,造成冲突。

如果出现了符号冲突一定要解决:如本例中,假设 main 不可变,已经包含了 lib 的代码。plugin.so 可通过 gcc 的 -Wl,-Bsymbolic选项告诉加载器优先使用自己的符号,而不优先用全局的符号。该选项可以解决符号冲突。

TIPS: 如果想观察加载器的工作,可以使用环境变量 LD_DEBUG=all ./main 来执行程序,会获得详细的解析过程。manpage的 ld.so(8) 有更多详细的说明。

最后附上示例用的代码:

➜  sample cat lib.h
#ifndef UNTITLED_LIB_H
#define UNTITLED_LIB_H

void lib_func();

#endif //UNTITLED_LIB_H
➜  sample cat lib.c
#include 
#include "lib.h"

void lib_func() {
    //fprintf(stderr, "%s()
", __func__); 
    fprintf(stderr, "debug:%s()
", __func__);
}
➜  sample cat main.c  
#include 
#include 
#include 
#include "lib.h"

int main() {
    void *handle = dlopen("./plugin.so", RTLD_NOW);
    void (*plugin_func)() = (void (*)()) dlsym(handle, "plugin");
    plugin_func();
    return 0;
}
➜  sample cat plugin.c 
#include "lib.h"

void plugin() {
    lib_func();
}
➜  sample cat Makefile 
all:main plugin

main:
    cc -o main main.c lib.c -ldl -rdynamic
plugin:plugin.c lib.c
    #cc -shared -fPIC -o plugin.so plugin.c lib.c -Wl,-Bsymbolic
    cc -shared -fPIC -o plugin.so plugin.c lib.c

clean:
    rm -f main plugin.so
➜  sample 

(陈国 | 天存信息)

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

解决动态库的符号冲突

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

解决动态库的符号冲突

一次debug遇到的疑惑某天发现一个程序有点问题,祭上print大法。 一次debug遇到的疑惑某天发现一个程序有点问题。祭上print大法,在关键的 lib_func() 函数里添加 print 调试信息,重新编译运行。期望 print 出的信息一点都
解决动态库的符号冲突
2020-12-02

linux 下同名符号冲突问题解决方案

linux 下同名符号冲突问题解决方案 最近的工作中遇到如下令人蛋疼的问题: Linux 下有三个模块aa、bb、cc,基本情况如下: cc 编译连接得到 cc.so 动态库,cc 中有如下接口:cc_fun { …… do();//
2022-06-04

Android滑动冲突的完美解决

Android滑动在智能手机上是必备的操作,但是在开发的时候,你是否和我一样,经常会遇到滑动冲突的问题,比如最简单需要在ListView里面添加一个侧滑动作,这时候冲突时必然的,那我们该如何解决这个问题呢? 先来说一下滑动冲突都有那些,该
2022-06-06

win10的1903驱动冲突怎么解决

本篇内容介绍了“win10的1903驱动冲突怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!第一种方法 1.找到桌面上的【此电脑】图标
2023-07-01

Android listview的滑动冲突解决方法

Android listview的滑动冲突解决方法 在Android开发的过程中,有时候会遇到子控件和父控件都要滑动的情况,尤其是当子控件为listview的时候。就比如在一个ScrollView里有一个listview,这种情况较常见,就
2022-06-06

android多种滑动冲突的解决方案

一、前言 Android 中解决滑动的方案有2种:外部拦截法 和内部拦截法。 滑动冲突也存在2种场景: 横竖滑动冲突、同向滑动冲突。 所以我就写了4个例子来学习如何解决滑动冲突的,这四个例子分别为: 外部拦截法解决横竖冲突、外部拦截法解决同
2022-06-06

Android滑动冲突问题的解决方法

叙述滑动冲突可以说是日常开发中比较常见的一类问题,也是比较让人头疼的一类问题,尤其是在使用第三方框架的时候,两个原本完美的控件,组合在一起之后,忽然发现整个世界都不好了。 关于滑动冲突滑动冲突分类 滑动冲突,总的来说就是两类。 1、同方向滑
2022-06-06

Android滑动冲突的完美解决方案

关于滑动冲突 在Android开发中,如果是一些简单的布局,都很容易搞定,但是一旦涉及到复杂的页面,特别是为了兼容小屏手机而使用了ScrollView以后,就会出现很多点击事件的冲突,最经典的就是ScrollView中嵌套了ListView
2022-06-06

Android滑动事件冲突的解决方法

滑动是Android中不可缺少的一部分,多个滑动必然会产生冲突,比如我们最常见的是ScrollView中嵌套了ListView,一般做法是计算出ListView的总高度,这样就不用去滑动ListView了。又比如一个ViewPager嵌套F
2022-06-06

Android中DrawerLayout+ViewPager滑动冲突的解决方法

DrawerLayout 是 Android 官方的侧滑菜单控件,而 ViewPager 相信大家都很熟悉了。今天这里就讲一下当在 DrawerLayout 中嵌套 ViewPager 时,要如何解决滑动冲突的问题,效果如下:首先,让我们先
2023-05-31

浅谈Android View滑动冲突的解决方法

引言 这一篇文章我们就通过介绍滑动冲突的规则和一个实例来更加深入的学习View的事件分发机制。 1、外部滑动方向和内部滑动方向不一致 考虑这样一种场景,开发中我们经常使用ViewPager和Fragment配合使用所组成的页面滑动效果,很多
2022-06-06

android中view手势滑动冲突的解决方法

Android手势事件的冲突跟点击事件的分发过程息息相关,由三个重要的方法来共同完成,分别是:dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent。public boolean disp
2022-06-06

怎样采用JSI解决不同类库间的冲突

怎样采用JSI解决不同类库间的冲突,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。采用JSI解决不同类库间的冲突众所周知, Scriptaculous所依赖的Prototype库
2023-06-03

如何解决Jquery库及其他库之间的$命名冲突

这篇文章介绍了Jquery库及其他库之间的$命名冲突的解决方法,有需要的朋友可以参考一下
2022-11-15

Android应用中的View出现滑动冲突如何解决

本篇文章给大家分享的是有关Android应用中的View出现滑动冲突如何解决,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1、外部滑动方向和内部滑动方向不一致考虑这样一种场景,
2023-05-31

编程热搜

目录