C++ ODR规则与dlopen 问题

问题

开发平台*.so插件的时候遇到相同的函数名称出现在不同的.so文件中,假设分别为a.so和b.so,b.so要使用a.so中的定义函数 a(),而在dlopen会先加载a.so然后加载b.so,打开b.so时,会报空指针错误。

  基本概念

ODR在C++标准中被解释为:

1.任何编译单元都不能包含变量、函数、枚举、类或者模板的定义一次以上。

2.所有程序必须且只能包含一次其中用到的所有非内联函数和对象。

3.在需要类的完整定义的编译单元中,类的定义必须且只能出现一次。

4.包括类、枚举、类模板......等等在内的一些定义可以在一个程序中出现多次,但是必须满足以下条件:

(1)所有定义的token序列必须相同(token你可以认为就是有效的语言要素,出了空白、换行注释之类的)

(2)所有的命名查找必须指向同一个实体,也就是说,你不能搞一些命名空间 typedef之类的,让这些相同的token表示不同的意义

(3)所有运算符必须表示同一个重载

(4)对于你要定义的实体中的所有带默认参数的函数,默认参数必须满足以上三条

(5)对于类定义,构造函数中调用的基类构造函数必须是同一个

总而言之,这个第四条的意思就是不同的定义之间不能有任何歧义。

解决方案:

通过分析可知,对于这种情况下跨.so调用函数,需要将函数名称在编译的时候就要对外暴露,不然外部.so会查找不到该函数的定义。

具体方式,在a.so编译中添加a.map文件,其中需要添加要对外暴露的函数。同事需要修改Makefile文件。具体内容如下:

暴露方式为在文在a.map文件中设置Global和Local的函数名称 并通过编译参数指定该内容进行编译:

编译命令:

1 gcc -Wall -g -fPIC -shared ./a.c -o a.so -Wl,--version-script=a.map

Map文件a.map

1 {
2 global:
3     global_fun_name;
4 local:*;
5 }; 
时间: 2024-10-18 10:47:44

C++ ODR规则与dlopen 问题的相关文章

C++ 内联函数

1.定义: 被调用函数的函数体代码直接插入到该函数被调用处, 而不是通过call语句进行. 2.方式: (1).类的定义体外: 当在类的定义体外时,需要在该成员函数的定义前面加“inline”关键字,显式地告诉编译器该函数在调用时需要“内联”处理,如: class Person { public: string GetName(); private:   string  name; }; inline string GetName() {         return name; } (2).类

C++应用程序性能优化(三)——C++语言特性性能分析

C++应用程序性能优化(三)--C++语言特性性能分析 一.C++语言特性性能分析简介 通常大多数开发人员认为,汇编语言和C语言比较适合编写对性能要求非常高的程序,C++语言主要适用于编写复杂度非常高但性能要求并不是很高的程序.因为大多数开发人员认为,C++语言设计时因为考虑到支持多种编程模式(如面向对象编程和范型编程)以及异常处理等,从而引入了太多新的语言特性.新的语言特性往往使得C++编译器在编译程序时插入了很多额外的代码,会导致最终生成的二进制代码体积膨胀,而且执行速度下降.但事实并非如此

FindBugs规则整理

FindBugs规则整理 FindBugs是基于Bug Patterns概念,查找javabytecode(.class文件)中的潜在bug,主要检查bytecode中的bug patterns,如NullPoint空指针检查.没有合理关闭资源.字符串相同判断错(==,而不是equals)等 一.Security 关于代码安全性防护 1.Dm: Hardcoded constant database password (DMI_CONSTANT_DB_PASSWORD) 代码中创建DB的密码时采

make的使用和Makefile规则和编程及其基本命令(简单)

转自:http://blog.chinaunix.net/uid-23929712-id-2650328.html 概述: make从Makefile中文件中获取模块间的依赖关系,判断哪些文件已经过时,根据这些信息make确定哪些文件需要重新编译,然后使用Makefile中的编译命令进行编译 make命令参数详解 -C dir:在读取Makefile文件前,先切换到"dir"目录下,也就是把dir作为当前目录 -d     :make执行时打印出所有的调试信息 -e     :不允许在

加载动态链接库——dlopen dlsym dlclose

DLOPEN?DLMOPEN?DLCLOSE NAME ????dlclose, dlopen, dlmopen - 打开/关闭共享对象 SYNOPSIS #include <dlfcn.h> void *dlopen(const char *filename, int flags); int dlclose(void *handle); #define _GNU_SOURCE #include <dlfcn.h> void *dlmopen (Lmid_t lmid, const

Caliburn.Micro学习笔记(一)----引导类和命名匹配规则

Caliburn.Micro学习笔记(一)----引导类和命名匹配规则 用了几天时间看了一下开源框架Caliburn.Micro 这是他源码的地址http://caliburnmicro.codeplex.com/ 文档也写的很详细,自己在看它的文档和代码时写了一些demo和笔记,还有它实现的原理记录一下 学习Caliburn.Micro要有MEF和MVVM的基础 先说一下他的命名规则和引导类 以后我会把Caliburn.Micro的 Actions IResult,IHandle ICondu

eclipse使用与java语法规则

eclipse的使用 1.运行点击"三角图标"或右键Run As运行2.3. java语法规范 1.括号要成对出现2.每句代码应该有分号结束3.java语法区分大小写4.一个文件只能写一个带有public的class声明,还必须和文件名一致.一个文件中不可以有多个带有public的修饰符号5.名称写的时候不要包含关键字和非法字符(字母和下划线开头可以,也可以用数字结尾)6.java代码的语法全部都是半角符号7.学会规范的写代码. 写代码的好习惯: 1.常按保存,写完一句或几句就按一次C

Git忽略规则.gitignore梳理

. 在已忽略文件夹中不忽略指定文件夹 /node_modules/* !/node_modules/layer/ 2. 在已忽略文件夹中不忽略指定文件 /node_modules/* !/node_modules/layer/layer.js [注意项]注意写法 要忽略的文件夹一定要结尾 /* ,否则不忽略规则将无法生效 3. 其他规则写法 (附)   以斜杠"/"开头表示目录: 以星号"*"通配多个字符: 以问号"?"通配单个字符 以方括号&q

Javascript类型转换的规则实例解析

http://www.jb51.net/article/79916.htm 类型转换可以分为隐式转换和显式转换,所谓隐式转换即程序在运行时进行的自动转换,显式转换则是人为的对类型进行强制转换.Javascript的变量是松散类型的,它可以存储Javascript支持的任何数据类型,其变量的类型可以在运行时被动态改变.请看示 例: ? 1 2 3 var n = 10; n = "hello CSSer!"; n = {}; 上面的示例中,首先声明n变量并初始化其值为10(整数类型),接