[英]How -fvisibility-inlines-hidden differs from -fvisibility=hidden in gcc
[英]Why `-fvisibility-inlines-hidden` is not the default?
我想看看我的理解是否正确。
inline
是对C ++编译器的建议,用于在函数看到更好时替换函数,因此调用标记为从库外部内联的过程不应该是可靠的,并且它们在逻辑上应该默认隐藏,防止其他人将它们称为更新到编译器或代码库可以改变决定(从而删除inline
d函数和ABI破坏?)。
但是,它似乎不是默认设置,并且应设置-fvisibility-inlines-hidden
以使其发生。 我问这里为什么会这样? 没有设置任何真实的用例,它只是因为遗留的原因?
它们在逻辑上应默认隐藏
C ++要求所有函数(包括inline
函数)在所有翻译单元中具有相同的地址。 所有翻译单位也应共享本地静态。 如果将程序构建为多个共享对象(.so文件),则隐藏内联函数会违反这些要求。
内联函数应具有公共可见性,以便动态链接器可以在运行时从所有现有选项中选择一个定义。
GCC 维基提到:
-fvisibility-inlines-hidden
可以在没有源更改的情况下使用, 除非您需要覆盖地址标识对于函数本身或任何函数本地静态数据很重要的内联 。
考虑以下示例。 可执行来源:
// main.cpp
#include <cstdio>
struct A { };
inline A &foo()
{
static A a;
return a;
}
int main()
{
void *p = &foo();
std::printf("main() - %p\n", p);
}
共享对象源:
#include <cstdio>
struct A { };
inline A &foo()
{
static A a;
return a;
}
static __attribute__((constructor)) void init()
{
void *p = &foo();
std::printf("main() - %p\n", p);
}
如果您针对此共享对象构建了两者并链接可执行文件,则可以看到foo
始终在两个翻译单元中返回相同的地址。
现在,如果将__attribute__((visibility("hidden")))
到这些内联函数,那么您将看到不同翻译单元中的地址不同。
这不是某些C ++程序可能期望的。
今天大多数人认为inline
与实际函数内联无关。 这不完全正确。 ELF目标尝试使动态链接透明,例如,如果程序构建为单个可执行文件或多个共享对象,则程序应该具有相同的行为。
为了使ELF成为可能,需要通过GOT或PLT调用所有具有公共可见性的功能,就好像它是“导入”功能一样。 这是必需的,以便每个函数都可以被另一个库(或可执行文件本身)覆盖。 这也禁止内联所有公共非内联函数(参见3.5.5节,其中显示PIC中的公共函数调用应通过PLT进行)。
公共内联函数的代码内联是可能的,因为当内联函数的多个定义不相等时,内inline
允许程序行为未定义。
有趣的说明:Clang违反了ELF的要求,无论如何都能够在ELF目标上内联公共功能。 GCC可以使用-fno-semantic-interposition
标志执行相同的操作。
inline
是对C ++编译器的建议,用于在函数看到更好时替换它
不是。最初的情况可能是90年代后期,但很长一段时间都没有。
请参阅此答案以获得更好的解释。
因此,从库外部调用标记为内联的过程应该不可靠
即使编译器内联调用(它可能有或没有做inline
关键字),这是在一个特定调用位置完成。 内联不是函数发生的事情,必须始终像往常一样发出,而是函数调用 。
编译器完全可以内联对函数的一些调用而不是其他调用,这取决于它对将在调用站点产生最佳代码的意见。
现在,目前还不清楚你认为图书馆中的inline
原因是什么问题,因此很难直接解决这个问题。
inline是对C ++编译器的建议,用于在函数看到更好时替换函数,因此调用标记为从库外部内联的过程不应该是可靠的并且它们在逻辑上应该默认隐藏
编译器仍然可以决定内联一些调用,并使其中一些调用无内联。 在这种情况下,您将在链接在一起的所有库中获得内联函数的多个副本。
此外,标准有点要求&foo
在你的程序中到处都是相同的地址,尽管标准没有提及DSO / DLL的任何内容,因此编译器在这些方面有一些自由(事实上,MSVC遵循相反的方法留下一切默认隐藏)。
但是,它似乎不是默认设置,并且应设置-fvisibility-inlines-hidden以使其发生。
尽管名称, -fvisibility-inlines-hidden
仅影响内联类成员函数。 对于其他一切, -fvisibility=hidden
应该足够了。
没有设置任何真实的用例,它只是因为遗留的原因?
是。 IIRC旗帜在GCC 3.2中实施(或足够接近); 将其设为默认会破坏许多遗留代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.