Linker 在哪种情况下允许C编译器忽略调用约定?

Linker 在哪种情况下允许C编译器忽略调用约定?,linker,shared-libraries,calling-convention,abi,Linker,Shared Libraries,Calling Convention,Abi,出于显而易见的原因,C编译器必须编译其他共享库在外部可见的所有函数,以便它们符合平台的调用约定和其他ABI要求。但是,我了解到,对于可以保证永远不会从外部模块调用的函数,不一定需要这样做 编译器如何以及何时才能确定给定函数是否为真 静态函数仅对同一编译单元中的其他函数可见,因此,对于这种破坏ABI的优化来说,它是一个很好的候选者。但是指向静态函数的函数指针仍然可以传递给其他模块。编译器是否尝试确定函数指针是否在代码中的任何位置传递 gcc编译器具有允许将符号声明为默认、隐藏甚至内部的功能,文档

出于显而易见的原因,C编译器必须编译其他共享库在外部可见的所有函数,以便它们符合平台的调用约定和其他ABI要求。但是,我了解到,对于可以保证永远不会从外部模块调用的函数,不一定需要这样做

编译器如何以及何时才能确定给定函数是否为真

  • 静态函数仅对同一编译单元中的其他函数可见,因此,对于这种破坏ABI的优化来说,它是一个很好的候选者。但是指向静态函数的函数指针仍然可以传递给其他模块。编译器是否尝试确定函数指针是否在代码中的任何位置传递

  • gcc编译器具有允许将符号声明为默认、隐藏甚至内部的功能,文档中特别提到,这些信息可用于执行某些外部可见函数无法执行的优化。如果函数指针被传递给注释为内部函数的外部代码,会发生什么情况

在保证与其他库的互操作性的同时,帮助编译器执行尽可能多的优化的最佳方法是什么?我是否应该使用编译器选项将所有函数定义为内部函数,并使用需要在外部可见的所有函数的属性覆盖该选项

静态函数仅对同一编译单元中的其他函数可见,因此,对于这种破坏ABI的优化来说,它是一个很好的候选者。但是指向静态函数的函数指针仍然可以传递给其他模块。编译器是否尝试确定函数指针是否在代码中的任何位置传递

是的,编译器进行“转义分析”,以查看给定函数是否仅在内部使用,或者是否通过其指针转义

gcc编译器有一些扩展,允许将符号声明为默认、隐藏甚至内部,文档中特别提到,这些信息可用于执行某些外部可见函数无法执行的优化。如果函数指针被传递给注释为内部函数的外部代码,会发生什么情况

请看我对第一点的回答。

C标准要求在所有情况下,指向同一函数的两个指针比较相等

如果将符号声明为外部,并且指针从未传递给外部代码,则编译器只能执行ABI中断技巧

编译器是否尝试确定是否传递了函数指针 代码中的任何地方

是的,如果它想执行此优化,它会这样做。编译器可以很容易地知道哪些函数执行了函数指针衰减,因此知道是否获取了函数的地址并不是什么大问题。保守地说,编译器可以假设所有函数指针都传递给外部代码,或者它们可能尝试更高级的东西

如果将函数指针传递给外部代码,会发生什么情况 对于注释为内部的函数

没什么大不了的——它一定有用

内部/外部可见性主要是关于可见性。编译器只能在相对较少的情况下将其转换为打破ABI的许可证

我是否应该使用编译器选项将所有函数定义为 内部,并为所有 是否需要外部可见


除非您的库仅由一个翻译单元组成,否则您可能希望几乎所有函数都需要外部可见。在C语言中,“外部但仅在我的库中”和“所有外部”之间没有什么有意义的区别。然而,理论上,你可以试试这个。但是,我怀疑您是否能获得很大的加速,对于一个非常重要的代码库来说,这将是一项艰巨的工作。

在某些ARM系统上,如果代码期望浮点值以与其他参数相同的方式传递,或者在FP寄存器中传递,则可能会存在兼容性困难。如果不是函数指针,我认为这个问题可以通过使用FPU生成代码的编译器来解决,该编译器使用FPU寄存器和“弱链接”生成一个名称有误的函数版本具有未损坏名称的包装器,该包装器将普通参数复制到FPU寄存器并调用损坏的命名版本。使用FPU并希望调用FPU寄存器版本的编译器编译代码将生成对损坏名称版本的调用,以及一个弱链接的包装器,它将FPU寄存器复制到普通参数并调用未损坏的版本。这应该允许调用方和被调用代码FPU使用的任意组合之间的“通用”行为。至于函数指针,我认为人们可以通过说除非声明“特别”它们总是指向使用最基本ABI的方法来回避ABI差异的问题。这看起来可行吗?