我目前正在使用GCC为QNX(x86)开发一个库,我想制作一些在库中专用的符号,对其他模块是不可见的,特别是对使用该库的代码。
这已经成功了,但是,在研究如何实现它时,我在GCC的文档中找到了一个非常令人担忧的段落(参见http://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Code-Gen-Options.html#Code-Gen-Options,flag -fvisibility的解释):
尽管有命名法,但默认总是意味着公开;即,可以从共享对象外部链接。 protected和internal在实际使用中相当无用,因此隐藏了唯一的其他常用选项。默认情况下if -fvisibility未指定为默认值,即将每个符号设为公共 - 这会导致与以前版本的GCC相同的行为。
我对“内部”在实际使用中的可见性非常感兴趣。根据我从GCC文档(http://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Function-Attributes.html#Function-Attributes,可见性属性的解释)的另一段中所理解的,可见性“内部”甚至比“隐藏”的可见性更强(对我来说更有用):
内部可见性就像隐藏的可见性,但具有额外的处理器特定语义。除非psABI另有规定,否则GCC定义内部可见性意味着永远不会从另一个模块调用函数。将其与隐藏函数进行比较,隐藏函数虽然不能被其他模块直接引用,但可以通过函数指针间接引用。通过指示不能从模块外部调用函数,GCC可以例如省略PIC寄存器的加载,因为已知调用函数加载了正确的值。
任何人都可以深入解释一下吗?
如果您只想隐藏内部符号,请使用-fvisibility=hidden
。它完全符合你的要求。
internal
旗比hidden
旗更进一步。它告诉编译器ABI兼容性并不重要,因为模块外的任何人都不会使用该函数。如果某些外部代码确实设法调用该函数,它可能会崩溃。
不幸的是,有很多方法可以将internal
函数意外暴露给外界,包括函数指针和C ++虚方法。例如,许多库使用回调来发送事件信号。如果您的程序使用其中一个库,则绝不能使用internal
函数作为回调。如果这样做,编译器和链接器将不会发现任何错误,并且您的程序将具有细微的,难以调试的崩溃错误。
即使您的程序现在不使用函数指针,当所有人(包括您)忘记此限制时,它可能会在未来几年开始使用它们。牺牲安全性以获得微小的性能提升通常是一个坏主意,因此internal
可见性不是建议的项目范围默认值。
如果您正在尝试优化一些使用频繁的代码,那么internal
可见性会更有用。您可以使用__attribute__ ((visibility ("internal")))
标记这些少数特定函数,它告诉编译器速度比兼容性更重要。你也应该为自己留言,所以你要记得永远不要指向这些功能。
我无法提供深入的答案,但我认为“内部”可能不实用,因为它依赖于处理器。您可能会在某些系统上获得预期的行为,但在其他系统上,您只能“隐藏”。