zoukankan      html  css  js  c++  java
  • 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 }; 

      

  • 相关阅读:
    .NET中操作SQLite
    Visual Studio 快捷键
    ADO.NET入门教程(三) 连接字符串,你小觑了吗?
    ADO.NET入门教程(二)了解.NET数据提供程序
    Xaml语法概述及属性介绍
    Csharp日常笔记
    C#基础
    PAT-L3-球队“食物链”-dfs-状压-set
    TOJ1302: 简单计算器 && TOJ 4873: 表达式求值&&TOJ3231: 表达式求值
    TOJ 3973 Maze Again && TOJ 3128 简单版贪吃蛇
  • 原文地址:https://www.cnblogs.com/ibyte/p/5742084.html
Copyright © 2011-2022 走看看