gcc中_GLIBCXX_VISIBILITY的含义和DSO

gcc中_GLIBCXX_VISIBILITY的含义和DSO

背景

在查看gcc中包含的一些标准标头的来源(在/usr/include/c++/中),并在每个标头的顶部找到以下内容

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

	//...

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace

究竟是什么_GLIBCXX_VISIBILITY(default)

源文件:gcc-9.1.0/libstdc+±v3/include/bits/c++config

// Macros for visibility attributes.
//   _GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY
//   _GLIBCXX_VISIBILITY
#define _GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY

#if _GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY
# define _GLIBCXX_VISIBILITY(V) __attribute__ ((__visibility__ (#V)))
#else
// If this is not supplied by the OS-specific or CPU-specific
// headers included below, it will be defined to an empty default.
# define _GLIBCXX_VISIBILITY(V) _GLIBCXX_PSEUDO_VISIBILITY(V)
#endif

// Inline namespace for symbol versioning.
#if _GLIBCXX_INLINE_VERSION
# define _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace __8 {
# define _GLIBCXX_END_NAMESPACE_VERSION }

因此,如果_GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY为真,那么,它将扩展为:

__attribute__ (( __visibility__ ("default")))

如果_GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY为假,则无效。

__visibility__属性用于定义DSO文件中符号的可见性。可以用来隐藏DSO之外的符号。

例如:

__attribute__ ((__visibility__("default"))) void foo();
__attribute__ ((__visibility__("hidden"))) void bar();

函数foo()可以在DSO外部使用,而bar()基本上是私有的,只能在DSO中使用。

您可以在此处详细了解__visibility__属性:https://gcc.gnu.org/wiki/Visibility

限制符号可见性的原因:从动态库中尽可能少地输出符号是一个好的实践经验。输出一个受限制的符号会提高程序的模块性,并隐藏实现的细节。动态库装载和识别的符号越少,程序启动和运行的速度就越快。导出所有符号会减慢程序速度,并耗用大量内存。

“default”:用它定义的符号将被导出,动态库中的函数默认是可见的。

”hidden”:用它定义的符号将不被导出,并且不能从其它对象进行使用,动态库中的函数是被隐藏的。default意味着该方法对其它模块是可见的。而hidden表示该方法符号不会被放到动态符号表里,所以其它模块(可执行文件或者动态库)不可以通过符号表访问该方法。

要定义GNU属性,需要包含__attribute__和用括号括住的内容。可以将符号的可见性指定为visibility(“hidden”),这将不允许它们在库中被导出,但是可以在源文件之间共享。实际上,隐藏的符号将不会出现在动态符号表中,但是还被留在符号表中用于静态链接。

导出列表由编译器在创建共享库的时候自动生成,也可以由开发人员手工编写。导出列表的原理是显式地告诉编译器可以通过外部文件从对象文件导出的符号是哪些。GNU用户将此类外部文件称作为”导出映射”

DSO 是什么

DSO动态共享对象,或者更不正式的shared library

什么是隐藏符号

隐藏符号是一个符号(即函数或数据对象的名称) 已使用隐藏链接编译,例如根据(GCC具体) 声明:

int x __attribute__ ((visibility ("hidden")));

如果它被隐藏了怎么能被引用

它不可能,这是你被警告的内容。例如。链接时间警告:

隐藏符号stat;在/usr/lib/libc_nonshared.a(stat.oS中由DSO引用
“hidden symbol `stat’ in /usr/lib/libc_nonshared.a(stat.oS) is referenced
by DSO”

告诉您链接中的DSO引用了符号stat,和 链接器可以在stat中找到/usr/lib/libc_nonshared.a的定义, 但(显然)该定义不在引用它的DSO中 并且不能从该DSO引用,因为它是隐藏的。

如果问题DSO未正确构建以供使用,则会出现此问题 作为DSO。见this example 并按照解决方案的后续行动。

继续进行OP的跟进

如果某些DSO已经引用了隐藏符号,那么为什么问题出在DSO上?

链接器说:

DSO X包含对符号S的引用。我可以找到符号S的定义是另一个链接模块Y, 但是该定义无法满足X 动态中的引用(即在运行时),因为SY模块中隐藏了链接}}

我可以确认问题来自非共享对象[…] [但]我没有在我的非共享对象中明确隐藏这些符号。

您可能没有明确标记隐藏在非共享对象中的任何符号。根据它的构建方式,符号 默认情况下可能会隐藏,除非明确标记。

假设非共享对象为Y,并且涉嫌隐藏的符号为libnonshared.a。运行:

foo

获取有关objdump -t libnonshared.a中符号的信息。在输出中,查找libnonshared.a的条目。它是否包含标记foo? - 例如

.hidden

此条目表示0000000000000000 g F .text 000000000000000b .hidden foo是一个全局符号(标记为foo - 这就是链接器能够看到它的原因)它隐藏动态链接。

如果情况确实如此,那么您需要修复g的版本,以便它不会隐藏libnonshared.a。 否则该符号无被引用

reference

[1]. https://blog.csdn.net/fengbingchun/article/details/78898623

[2]. https://www.thinbug.com/q/29270208

[3]. https://www.thinbug.com/q/23696585

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Erice_s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值