确切地说,“-fno-语义插入”与“ -fvisibility = protected”有何不同?

时间:2018-07-07 23:11:36

标签: c++ c gcc elf

来自https://gcc.gnu.org/onlinedocs/gcc-8.1.0/gcc/Optimize-Options.html#index-fsemantic-interposition

  

-fsemantic-interposition

     

某些对象格式(例如ELF)允许动态链接器插入符号。这意味着对于从DSO导出的符号,编译器无法执行程序间传播,内联和其他优化,因为预期所讨论的功能或变量可能会发生变化。尽管此功能很有用,例如,通过调试实现重写内存分配功能,但在代码质量方面却很昂贵。使用-fno-semantic-interposition,编译器假定如果函数发生插入,则覆盖函数将具有完全相同的语义(和副作用)。同样,如果变量发生插入,则变量的构造函数将相同。该标志对于显式声明为内联的函数(不允许插入以更改语义)不起作用,而对于显式声明为弱的符号无效。

来自https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-visibility-function-attribute

  

受保护的

     

受保护的可见性类似于默认可见性,不同的是它表示定义模块中的引用绑定到该模块中的定义。也就是说,声明的实体不能被另一个模块覆盖。

听起来完全一样。

除了-fno-semantic-interposition明确地将标记为default的任何功能更改为protected以外,还有什么实际区别?

2 个答案:

答案 0 :(得分:1)

这个问题很难回答,因为当前-fsemantic-interposition实际上不起作用。在此示例中,

int a;

int
f1 (int a)
{
  return a;
}

int
f2 (void)
{
  return f1 (a) - a;
}

f2的主体即使使用return 0;(也可以使用-O2 -fsemantic-interposition有效地优化为-O2 -fno-semantic-interposition,以防文档中的选项含义颠倒) 。 I filed a bug.

可能的目的是-fsemantic-interposition会禁用此类优化,因此您最终需要调用f1 对结果进行显式计算。

ELF符号可见性与之实际上并不相关,主要是因为它仅适用于动态链接。链接编辑器仍可以在静态链接时插入符号(例如,使用-z muldefs选项),因此编译器应该确实提供一种启用插入而无需更改符号属性的方式(因此除__attribute__ ((weak))以外的其他内容。

答案 1 :(得分:0)

-fno-semantic-interposition应该与代码生成有关。 -fvisibility=protected与符号属性有关。 protected的可见性早于-fsemantic-interposition,正如Ulrich Drepper的How to Write Shared Libraries所述,这是您不应该使用的可见性属性。

  

通用ELF ABI定义了另一种可见性模式:受保护。在   该方案对在同一对象中定义的符号的引用是   总是对本地满意。但是符号仍然在外面可用   DSO。这听起来像是通过以下方式优化DSO的理想机制   避免使用导出的符号(请参阅第2.2.7节),但事实并非如此。   处理对受保护符号的引用比   正常查找。问题是ISO C标准的要求。   该标准要求函数指针指向相同的   功能,可以比作平等。该规则将被违反   快速简单的实现受保护的对象   能见度。假设一个应用程序引用了   DSO中的选定功能。在DSO中还有另一个   引用所述功能的功能。指针在   该应用程序指向该功能的PLT条目   在应用程序的PLT中。如果是受保护的符号查找   会简单地返回内部函数的地址   DSO的地址会有所不同。   在没有此要求的编程环境中   在函数指针上使用受保护的可见性   将是有用的和快速的。但是由于通常只有   系统上动态链接程序的一种实现   tem,此实现必须处理C程序   同样,强烈建议不要使用受保护的对象。

如果您希望您的库引用其自身的全局变量而没有插入的可能性(并且由于避免了PLT,可以更快地使用函数),则首选方法是使用隐藏别名定义符号并在内部使用隐藏别名。