GCC:内部可见性“在现实世界的使用中毫无用处”?

Posted

技术标签:

【中文标题】GCC:内部可见性“在现实世界的使用中毫无用处”?【英文标题】:GCC: In what way is visibility internal "pretty useless in real world usage"? 【发布时间】:2014-02-18 02:25:21 【问题描述】:

我目前正在使用 GCC 为 QNX (x86) 开发一个库,并且我想制作一些仅在库中使用且对其他模块不可见的符号,尤其是使用该库的代码。

这已经可行,但是,在研究如何实现它时,我在 GCC 的文档中发现了一个非常令人担忧的段落(参见 http://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Code-Gen-Options.html#Code-Gen-Options,flag -fvisibility 的解释):

尽管有命名法,但默认总是意味着公开;即,可用 从共享对象外部链接。受保护和 internal 在实际使用中非常没用,所以唯一的其他 常用选项被隐藏。默认 if -fvisibility 不是 指定是默认值,即,使每个符号公开——这会导致 与以前版本的 GCC 的行为相同。

我对“内部”可见性在实际使用中毫无用处非常感兴趣。根据我从 GCC 文档的另一段(http://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Function-Attributes.html#Function-Attributes,对可见性属性的解释)的理解,可见性“内部”甚至比可见性“隐藏”更强(对我更有用):

内部可见性类似于隐藏可见性,但具有额外的 处理器特定的语义。除非 psABI 另有规定, GCC 定义内部可见性意味着函数永远不会 从另一个模块调用。将此与隐藏函数进行比较, 虽然它们不能被其他模块直接引用,但可以 通过函数指针间接引用。通过表明一个 函数不能从模块外部调用,GCC 可以用于 实例省略 PIC 寄存器的加载,因为已知 调用函数加载了正确的值。

谁能详细解释一下?

【问题讨论】:

【参考方案1】:

如果您只想隐藏内部符号,只需使用-fvisibility=hidden。它完全符合您的要求。

internal 标志比hidden 标志更进一步。它告诉编译器 ABI 兼容性并不重要,因为模块之外的任何人都不会使用该函数。如果某些外部代码确实设法调用了该函数,它可能会崩溃。

不幸的是,有很多方法可以意外地将internal 函数暴露给外界,包括函数指针和 C++ 虚方法。例如,许多库使用回调来发出事件信号。如果您的程序使用这些库之一,则绝不能使用internal 函数作为回调。如果你这样做了,编译器和链接器不会发现任何错误,而且你的程序会出现微妙的、难以调试的崩溃错误。

即使您的程序现在不使用函数指针,它也可能在几年后开始使用它们,那时每个人(包括您)都忘记了这个限制。为了微小的性能提升而牺牲安全性通常是一个坏主意,因此 internal 可见性不是推荐的项目范围默认设置。

internal 可见性在您尝试优化一些频繁使用的代码时会更有用。您可以使用__attribute__ ((visibility ("internal"))) 标记这几个特定功能,它告诉编译器速度比兼容性更重要。您还应该为自己留下评论,因此请记住永远不要使用指向这些函数的指针。

【讨论】:

感谢您的精彩解释。我想我误解了我在第一篇文章中引用的文档。我的印象是,可以通过某种方式从其他模块中获取指向隐藏函数的指针,并且在从外部世界隐藏相应函数时,从这个意义上讲,内部函数比隐藏函数更强大。我想我现在明白了。除此之外,调用内部无用有点令人担忧;如果是,为什么要支持?【参考方案2】:

我无法提供深入的答案,但我认为“内部”可能不切实际,因为它取决于处理器。您可能会在某些系统上获得预期的行为,但在其他系统上您只会“隐藏”。

【讨论】:

以上是关于GCC:内部可见性“在现实世界的使用中毫无用处”?的主要内容,如果未能解决你的问题,请参考以下文章

海湾合作委员会:可见度内部以什么方式“在实际使用中相当无用”?

在故障回调中改进内部设置textview可见性

Java 内部类可见性难题

Kotlin 中内部可见性修饰符的范围

github设置仓库可见性 私人仓库设置他人协作/可见

kotlin访问控制符可见性