GCC的符号可见性——解决多个…

_attribute__((visibility(“hidden“)))和符号可见性 通过配置符号的可见性,可以控制哪些符号在不同模块间可见,从而优化库的结构和提高安全性。是GCC/Clang提供的一种机制,用于控制符号的可见性,以。以下是一个简单示例,展示了如何使用。在C和C++中,符号可见性是指。提高代码安全性和优化链接性能。是实现这一目标的有效手段。不会出现在符号表中,而。 阅读详情

问题

最近项目遇到一些问题,场景如下

主程序依赖了两个库libA的funcA函数和libB的funcB函数。示意的代码(main.cpp)如下:

#include 

int funcA(int, int);
int funcB(int, int);

int main() {
    printf("%d,", funcA(2, 1));
    printf("%d\n", funcB(2, 1));
    return 0;
}

libA示意实现(libA.cpp)如下:

int subfunc(int a, int b) {
    return a + b;
}

int funcA(int a, int b) {
    return subfunc(a, b);
}

libB示意实现(libB.cpp)如下:

int subfunc(int a, int b) {
    return a - b;
}

int funcB(int a, int b) {
    return subfunc(a, b);
}

可见funcA调用了libA中的内部函数subfunc,funcB调用了libB中的内部函数subfunc,这两个subfunc实现不同,但不幸的是名字不小心起得一样了

这时我们尝试编译并运行:

g++ -fPIC libA.cpp -shared -o libA.so
g++ -fPIC libB.cpp -shared -o libB.so

g++ main.cpp libA.so libB.so -o main

export LD_LIBRARY_PATH=.
./main

我们期望的结果是3,1(funcA和funcB各自调用不同的subfunc实现),

实际得到的结果是3,3(funcA和funcB都调用了libA中的subfunc实现)

原因

我们通过readelf来查看符号:

$ readelf -a libA.so | grep subfunc
000000200a60  000200000007 R_X86_64_JUMP_SLO 0000000000000708 _Z7subfuncii + 0
     2: 0000000000000708    20 FUNC    GLOBAL DEFAULT   10 _Z7subfuncii
    45: 0000000000000708    20 FUNC    GLOBAL DEFAULT   10 _Z7subfuncii

$ readelf -a libB.so | grep subfunc 
000000200a60  000200000007 R_X86_64_JUMP_SLO 0000000000000708 _Z7subfuncii + 0
     2: 0000000000000708    22 FUNC    GLOBAL DEFAULT   10 _Z7subfuncii
    45: 0000000000000708    22 FUNC    GLOBAL DEFAULT   10 _Z7subfuncii

可见libA和libB里面都有subfunc符号,名字完全一样,而且都是GLOBAL的

GLOBAL的符号即全局的符号,同名的全局符号会被认为是同一个符号,由于main先加载了libA,得到了libA中的subfunc符号,再加载libB时,就把libB中的subfunc忽略了。

解决方案

这其实是符号的可见性(Symbol Visibility)问题,既然有GLOBAL符号,那自然会有LOCAL符号,LOCAL的符号只在当前lib可见,全局不可见。

如何将符号变成LOCAL的呢,最直接的就是加上visibility为hidden的标志,修改后的libA.cpp:

__attribute__ ((visibility ("hidden"))) int subfunc(int a, int b) {
    return a + b;
}

int funcA(int a, int b) {
    return subfunc(a, b);
}

再重新编译执行,可以得到结果为3,1,成功!这里再查看一下libA的符号:

$ readelf -a libA.so | grep subfunc
    40: 00000000000006a8    20 FUNC    LOCAL  DEFAULT   10 _Z7subfuncii

可见subfunc符号已经变成了LOCAL

默认LOCAL

上面的方法可以解决问题,但是,实际情况往往是,libA里面有很多的内部函数,而暴露给外部的只有少数,能不能指定少数符号为GLOBAL,其它的都是LOCAL呢?答案是肯定的,修改libA.cpp如下:

int subfunc(int a, int b) {
    return a + b;
}

__attribute__ ((visibility ("default"))) int funcA(int a, int b) {
    return subfunc(a, b);
}

这时,libA的编译参数需要加上-fvisibility=hidden:

g++ -fPIC libA.cpp -shared -fvisibility=hidden -o libA.so

同样可以解决问题。

跨平台兼容性

windows平台对于符号的行为是不一样的,windows默认动态库里符号是LOCAL的,通过__declspec(dllexport)来声明GLOBAL符号,所以可以用下面的方式来兼容:

#if defined _WIN32 || defined __CYGWIN__
  #ifdef BUILDING_DLL
    #ifdef __GNUC__
      #define DLL_PUBLIC __attribute__ ((dllexport))
    #else
      #define DLL_PUBLIC __declspec(dllexport) // Note: actually gcc seems to also supports this syntax.
    #endif
  #else
    #ifdef __GNUC__
      #define DLL_PUBLIC __attribute__ ((dllimport))
    #else
      #define DLL_PUBLIC __declspec(dllimport) // Note: actually gcc seems to also supports this syntax.
    #endif
  #endif
  #define DLL_LOCAL
#else
  #if __GNUC__ >= 4
    #define DLL_PUBLIC __attribute__ ((visibility ("default")))
    #define DLL_LOCAL  __attribute__ ((visibility ("hidden")))
  #else
    #define DLL_PUBLIC
    #define DLL_LOCAL
  #endif
#endif

隐藏外部依赖的符号

我遇到的实际情况比上面更复杂一些,subfunc并不是在libA中实现的,而是在另一个外部库libsubfunc.a中实现的。libA通过包含头文件来获取到这个函数:

#include "subfunc.h"

int funcA(int a, int b) {
    return subfunc(a, b);
}

上面的-fvisibility仅对实现生效,不能对声明生效。但libsubfunc.a是第三方库,我们不能去改它的代码,也不能改它的头文件,对于这种情况,gcc提供了下面方式来支持:

#pragma GCC visibility push(hidden)
#include "subfunc.h"
#pragma GCC visibility pop

int funcA(int a, int b) {
    return subfunc(a, b);
}

这种方式更方便灵活。

如果是dlopen载入so可以通过参数控制。

详见: http://blog.himdd.com/archives/3260

参考文档

GCC Visibility

source:https://github.com/wwbmmm/blog/wiki/gcc_visibility

GCC系列: __attribute__((visibility(““))) 在 objc-api.h 里面有很多关于__attribute__ 的定义. 例如 #if !defined(OBJC_VISIBLE) # if TARGET_OS_WIN32 # if defined(BUILDING_OBJC) # define OBJC_VISIBLE __declspec(dllexport) # else # ... 阅读详情

相关推荐

库文件中找不到符号问题:CMAKE_CXX_FLAGS: -fvisibility=hidden

问题描述: 编译出来的预测库发现找不到符号,但是相关源文件的确编译到库里了。 定位问题: cmake配置中打开了以下开关:

少安的砖厂 5759

GCC的符号可见性 -fvisibility=hidden

问题 主程序依赖了两个库libA的funcA函数和libB的funcB函数。示意的代码(main.cpp)如下: #include <cstdio> int funcA(int, int); int funcB(int, int); int main() { printf("%d,", funcA(2, 1)); printf("%d\n", funcB(2, 1)); return 0; } libA示意实现(libA.cpp)如下: int subfunc(in

qq_38350702的博客 1万+

GCC编译之如何控制共享文件导出符号

背景 前不久在调试一个与导出符号相关的bug,问题大概如此: 模块A.so在堆上构造了一个对象即 CTest *one = new CTest; , CTest在A.so定义,后来使用one->AMemFunc();,即调用一个成员函数时崩溃。原来在另一个模块B.so(比A.so先加载)中,也有一个同名的CTest定义,但是却没有一个叫AMemFunc的成员函数,因此崩溃。 那为什么A.so

Passers_B的专栏 9924

GCC 的 -fvisibility 参数

在 Windows 上使用 MSVC 创建和使用动态库时需要导出导入符号(参见Windows上动态库符号的导出和导入),但在 Linux 上使用 GCC 时,一般好像不需要导入导出符号。其实不然,GCC 编译时并不是不需要导出符号,而是默认导出了所有的符号。GCC 中也存在一个符号可见性的概念,称之为 Visibility,一般指的就是动态库中符号的可见性。默认情况下,动态库中的所有符号对于外部都是可见的,因此使用者可以直接使用动态库提供的函数。

qq_38370371的博客 1900

GCC的符号可见性——解决多个库同名符号冲突问题

问题 最近项目遇到一些问题,场景如下 主程序依赖了两个库libA的funcA函数和libB的funcB函数。示意的代码(main.cpp)如下: #include int funcA(int, int); int funcB(int, int); int main() { printf("%d,", funcA(2, 1)); printf("%d\n",

优快云明星博主,认证博客专家,视频、Matlab领域优质创作者。 3076

从理论到实践:使用Sigrity SystemSI完成DDR4信号完整性仿真全流程解析

本文详细解析了使用Sigrity SystemSI完成DDR4信号完整性仿真的全流程,从核心挑战到实战操作。文章深入探讨了DDR4信号完整性问题,介绍了SystemSI工具链的演进与分工,并提供了从前期准备到高级技巧的详细指南,帮助工程师有效解决DDR4设计中的信号完整性问题。

weixin_30505225的博客 511

GCC的符号可见性: 解决Linux多个库同名符号冲突问题以及引用不同版本库的问题

某项目中因为使用到了不同版本库的问题,因此整理下GCC的符号可见性问题,方便自己以后再次使用。

C/C++、嵌入式开发、深度学习算法、模型部署与推理优化 2125

详解modbus TCP通讯,并利用其实现欧姆龙PLC和西门子PLC的通讯

大家好,之前需要更新的MQTT通讯【2】因为硬件不足还不能发布出来,但最近在项目中涉及到西门子和欧姆龙之间的modbus TCP通讯,想到modbus TCP通讯是个非常常见并广泛使用的通讯协议,今天就结合最近做的测试给大家好好讲解一下,先提示一下,这边只给大家讲解如何实现,至于报文是什么,如何用socket来编写功能块或dll这边不会讲解,这块我会根据私信的小伙伴数量来考虑要不要出一篇如何用ST语言来编写modbus TCP功能块的博客。

dy186187的博客 1万+

__attribute__((visibility("default")))

-fvisibility=default|internal|hidden|protected gcc的visibility是说,如果编译的时候用了这个属性,那么动态库的符号都是hidden的,除非强制声明。 1.创建一个c源文件,内容简单 #include #include __attribute ((visibility("default"))) void not_

mowwwcom的专栏 970

【NLP】使用 PyTorch 从头构建自己的大型语言模型 (LLM)

如果我们在 n 维空间中绘制一个向量,看起来相似的物体(如狗和猫)将彼此靠近,而看起来不相似的物体(如学校和家庭)的嵌入向量将位于更远的地方。为此,我们将使用一种流行的标记器,称为 BPE 标记器,这是一种子词标记器,正在 GPT3 等模型中使用。:前馈网络使用深度神经网络来学习两个线性层(第一层有 d_model 节点,第二层有 d_ff 节点,根据注意力论文分配值)中嵌入向量的所有特征,并且将 ReLU 激活函数应用于第一线性层的输出,为嵌入值提供非线性,并应用 dropout 以进一步避免过度拟合。

sikh_0529的博客 1951

ROS2仿真抓取分拣案例,使用myCobot 280机械臂结合ROS2系统搭建机械分拣站

本案例展示了如何利用myCobot 280 urdf模型构建一个对象分类站,并在ROS2 jazzy中完成运动规划。

m0_71627844的博客 2126

C++符号可见性与符号冲突全解析

符号是编译器对代码元素(函数、变量、类等)的唯一标识,用于链接阶段的地址绑定。C 函数的符号通常为add(无修饰);C++ 函数因“名称修饰”(Name Mangling),符号会包含参数、返回值信息(如_Z3addii全局变量的符号直接为counter。同名符号会导致链接器或运行时“混淆”,引发冲突。符号可见性控制(如符号可见性是“预防措施”:通过visibility属性和减少不必要的符号暴露,从源头降低冲突概率;冲突解决策略。

bkspiderx的博客 1630

Maya ACES工作流程配置(Arnold 及 RedShift 贴图配置规范-还原出SP-Aces流程下贴图正确的效果) PS还原Aces流程下渲染的图

*如果使用SP,项目工程如果新建的时候设置的就是Aces的流程的话,按规范正常导出即可,贴图会带上相对应的后缀,然后贴图导入材质球的时候会根据后缀自动设置相对应的色彩空间;**万一不是,就自己手动设置一下对应的色彩空间即可;然后点击选择当前的或者选择全部导入的贴图,点击右下角后,开始转换;我复制了一下,一个默认没有LUT的效果,然后另外一个是加载2个LUT后的还原效果,和渲染的效果应该是没有区别的,至少我没有看出明显的区别;把需要转换的贴图拖拽到左侧,然后右面选择需要转换到的相对应的色彩空间;...

Yuulily 7994

【C/C++】g++ 和 gcc 生成库的符号可见性

方面gcc(C)g++(C++)默认可见性非 static 全局符号 default同左,但有更多隐式符号(vtable, RTTI 等)推荐控制方式同左,但需注意类、模板、异常等复杂情况.so 重要性高极高(ABI 稳定性依赖可见性).a 影响低低如有具体场景(如混合 C/C++、插件系统、跨平台等),可进一步细化策略。

lijian2017的博客 780

【电子元件篇】MOSFET场效应管作用、选型和测量指南-超简单解读

场效应管是一种电压控制型半导体器件,相比三极管具有输入阻抗高、噪声小、功耗低等优势。主要分为结型和绝缘栅型两大类,后者又可分为耗尽型和增强型MOS管。场效应管通过栅极电压控制漏极电流,具有转移特性和输出特性两大静态特性,以及快速的开关特性。其关键参数包括饱和漏源电流、夹断电压、跨导等,应用场景涵盖信号放大、恒流源、阻抗变换等领域。使用时需根据电路需求选择合适类型,如结型管适合一般放大,功率MOSFET适合高压大电流场合。检测时可用万用表电阻档初步判断好坏和放大能力。

2301_81299416的博客 2540

【微信小程序】微信小程序开发环境搭建:安装微信小程序开发者工具

通过本文的介绍,你应该已经成功安装并配置了微信小程序开发者工具,为微信小程序开发做好了准备。接下来,你可以开始编写你的第一个小程序项目,探索更多有趣的功能和特性。祝你开发顺利,创造更多优秀的作品!

墨夶的博客 2952

控制符号的可见性

http://my.huhoo.net/archives/2010/03/post-52.html  在普通的C语言中,如果您希望将函数或者变量限制在当前文件中,需要对其使用static关键字。然而,在一个包含很多文件的共享库中,如果您希望某个符号可以被共享库内部的几个文件访问,而又不提供给外部,则对符号进行隐藏处理就会比较困难。大多数的连接器都提供一些便利的方法来隐藏或者显示模块中

MyDriverC 1461

MAC-H3C官网inode客户端下载安装

MAC-H3C官网inode客户端下载安装

兴趣是最好的老师 1万+

GCC符号可见性:解决Linux C/C++多库符号冲突的工程实践

在Linux C/C++开发中,动态链接库(.so)的符号管理是构建复杂软件生态的基础。其核心原理在于ELF格式的符号解析机制与动态链接器的全局符号表管理。理解符号可见性控制的技术价值在于,它能有效避免因同名函数或变量冲突导致的运行时崩溃、内存错误等难以调试的问题,从而提升程序的稳定性和安全性。这一技术在大型项目、插件化架构、以及依赖多个第三方库的应用场景中尤为重要。通过编译选项如`-fvisibility=hidden`和链接器参数如`-Wl,--exclude-libs`,开发者可以精细控制符号的导出范

weixin_30321709的博客 390

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

gcc解决Linux多个动态库间的符号冲突问题

gcc动态库符号冲突解决办法

weixin_44834554的博客 4381

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

GCC制作动态库导出符号表

GCC制作动态链接库时默认会将所有的函数及变量都导出到符号表,正常情况下所有符号均导出是不会有问题的,但是有时会有问题。为了避免这种情况,就需要定制符号表,即仅仅将需要提供给其他模块使用的接口或变量导出到符号表,本文就是介绍制作这样的动态库的方法。

whb_fei的专栏 1万+

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

解析 GCC 符号可见性:__attribute__((visibility(“default“)))

很多开发者仅知道这行代码用于导出函数/变量,但并不清楚其底层原理、适用场景、配套规则、优缺点以及工程最佳实践。本文将从零开始,全方位拆解visibility 可见性属性,重点详解,搭配语法解析、底层机制、代码实战、避坑指南、工程规范,彻底吃透这一 Linux 开发核心知识点。是GCC/Clang 编译器专属扩展语法,不属于 C/C++ 标准语法,是编译器提供的代码属性修饰器。给函数、全局变量、结构体、类等代码实体附加特殊编译特性,指导编译器在编译、链接、符号导出阶段做定制化处理。

一个小孩 507
上一篇: 透过&nbsp;Linux&nbsp;内核看无锁编程
下一篇: linux下动态库的符号冲突、…
wakeupwakeup
博客等级 码龄11年 9粉丝 49原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值