为什么``````````````')''默认值不是默认值

Why `-fvisibility-inlines-hidden` is not the default?

本文关键字:默认值 为什么      更新时间:2023-10-16

我要看看我的理解是否正确。

inline是C 编译器的建议,以便在函数更好的情况下替换一个函数,因此将其称为"从图书馆外部"的程序标记为嵌套的过程不应可靠,并且在逻辑上应该默认隐藏它们,以防止他们称呼它们作为对编译器或代码库的更新可以更改决定(从而删除inline D功能和ABI断开?(。

似乎不是默认设置,应该设置-fvisibility-inlines-hidden来实现这一目标。我在这里问为什么是这种情况?是否设置具有任何真实用例

它们在逻辑上应默认隐藏

C 需要所有功能(包括inline功能(在所有翻译单元中具有相同的地址。也应在所有翻译单元之间共享本地静态。如果将程序作为多个共享对象(.SO文件(构建,则隐藏内联函数违反了这些要求。

内联函数应该具有公共可见性,以便动态链接器可以在运行时从所有现有的定义中选择一个定义。

GCC Wiki提到以下:

-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() - %pn", p);
}

共享对象来源:

#include <cstdio>
struct A { };
inline A &foo()
{
    static A a;
    return a;
}
static __attribute__((constructor)) void init()
{
    void *p = &foo();
    std::printf("main() - %pn", p);
}

如果您同时构建并链接可执行的对象,则可以看到foo总是在两个翻译单元中返回相同的地址。

现在,如果您将__attribute__((visibility("hidden")))添加到这些内联函数,那么您将看到该地址在不同的翻译单元中不同。

这不是某些C 程序可能期望的。


当今大多数人认为inline与实际功能内部无关。这不是完全正确的。精灵目标试图使动态链接透明,例如如果程序作为单个可执行文件或多个共享对象,则应行为相同。

使精灵需要所有具有公众可见性的功能,但要通过got或plt来调用,就好像它是"导入"功能一样。这是必需的,以便每个函数都可以被另一个库(或可执行文件本身(超越。这也禁止为所有公共非内部功能的插条(请参阅第3.5.5节,这表明应通过plt进行公共函数调用(。

代码对公共内联函数的代码恰好是可能的,因为inline允许在内联函数的多个定义不等的定义时,程序行为是不确定的。

有趣的说明:clang违反了这一精灵的要求,并且能够在小精灵目标上嵌入公共功能。GCC可以使用-fno-semantic-interposition标志。

inline是C 编译器的建议

否。最初是这种情况,也许是90年代后期,但很长一段时间都没有。

请参阅此答案,以提供一个很好的解释。

因此,调用从图书馆外部进行的标记的程序不应可靠

  1. 您的初始假设已经是错误的,因此因此,正在从错误的前提开始
  2. 即使编译器 do inline呼叫(它可以使用或不使用inline关键字(,这是在A 特定呼叫站点上完成的。插入并不是函数发生的事情,必须始终像往常一样发射,而是函数调用

    编译器完全有可能将某些呼叫置于函数,而不是其他电话,这取决于其对呼叫网站上最佳代码的看法。

现在,尚不清楚您认为库中的inline是什么问题,因此很难直接解决该问题。

内联是C 编译器在函数更好的情况下替换函数的建议,因此调用从库外部进行了标记为"从库外部"的过程不应可靠的,因此在逻辑上应该默认隐藏它们

编译器仍然可以决定内联一些呼叫,并将其中一些呼叫留下。在这种情况下,您将在所有要链接在一起的库中获得几个夹具函数的副本。

此外,标准在某种程度上要求&foo在您程序中的任何地方都具有相同的地址,尽管标准没有对DSO/DLL说任何内容,因此编译器在这些方面具有自由度(实际上,MSVC遵循相反的方法默认情况下留下所有东西(。


然而,似乎不是默认设置,应该设置-Fvisibilinsible-Inlines Hidden以实现这一目标。

尽管名称,-fvisibility-inlines-hidden仅影响内线的类成员函数。对于其他所有内容,-fvisibility=hidden就足够了。


没有设置具有任何真实用例的设置,并且仅仅是因为遗产原因?

是。IIRC该标志是在GCC 3.2(或足够接近(中实现的;使其默认会破坏很多旧的代码。