为什么 g++ 不生成"raw"符号?

Why doesn't g++ generate "raw" symbols?

本文关键字:raw 符号 g++ 为什么      更新时间:2023-10-16

从C中我们知道什么是合法的变量名。合法名称的通用正则表达式看起来类似于[w_](wd_)*

使用dlsym,我们可以加载任意字符串,并且c++在ABI中修改包含@的名称…

我的问题是:可以使用任意字符串吗?关于dlsym的文档似乎没有提到任何东西。

出现的另一个问题似乎意味着完全有可能有任意以null结尾的符号。这促使我提出以下问题:

为什么g++不发出带有名称和参数列表的原始函数签名,包括名称空间和类成员?

我的意思是:

namespace test {
class A
{
    int myFunction(const int a);
};
}
namespace test {
int A::myFunction(const int a){return a * 2;}
}

不被编译为

int ::test::A::myFunction(const int a)
相反,它在我的64位机器上被编译为-,使用g++ 4.9.2 -
0000000000000000 T _ZN4test1A10myFunctionEi

该输出由nm读取。代码使用g++ -c test.cpp -o out

编译。

我确信这个决定是务实地做出的,以避免对已有的C链接器(很可能甚至起源于cfront)进行任何更改。通过使用与C链接器相同的字符集发出符号,您不需要进行任何数量的更新,并且可以使用现成的链接器。

此外,C和c++是广泛可移植的语言,它们不希望冒险通过包含意外的符号来破坏更模糊的二进制格式(可能在嵌入式系统上)。

最后,由于您总是可以要求(例如gc++filt),因此使用全文表示似乎不值得。

注:您绝对不希望在函数名中包含参数名:如果重命名参数破坏了ABI,人们将不高兴。保持ABI兼容性已经够难的了。

GCC兼容Itanium c++ ABI。如果您的问题是"为什么Itanium c++ ABI要求以这种方式篡改名称?",那么答案很可能是

  1. 因为它的设计者认为这是个好主意
  2. 符号越短,对象文件越小,动态链接越快。
对于第二点,Ulrich Drepper的文章如何编写共享库中有很好的解释。
  1. 由于链接器(包括操作系统的动态链接器)对导出名称施加的限制-字符集,长度。正是由于这个原因,才出现了破损的现象。
    • 推论:在这些限制不存在的媒体中(各种使用自己的链接器的vm:例如。net, Java), mangling也不存在。
  2. 每个编译器产生的导出与其他编译器不兼容,必须使用不同的模式。因为link(静态或动态)不关心abi,它只关心标识符。

你基本上回答了你自己的问题:

合法名称的通用正则表达式看起来类似于[w_](wd_)*

从一开始,c++就使用了预先存在的(C)链接器/加载器技术。ld, ld-linux.so等都没有"c++"。

所以链接仅限于C语言中已经合法的内容。它不包括冒号、括号、与号、星号和其他任何您需要在纯文本中编码c++标识符的东西。

(在这个答案中,我忽略了您在::test::A::void myFunction(const int a)的示例中犯了几个错字)

格式为:

  • 不是programmer-specific;考虑到所有这些都是相同的,所以为什么要混淆人们:
    • int ::test::A::myFunction(const int)
    • int ::test::A::myFunction(int const)
    • int test::A::myFunction(int const)
    • int test :: A :: myFunction (int const)
    • 等等& help;
  • 明确
  • 简洁;没有参数名称或其他不必要的装饰
  • 更容易解析(注意每个组件的长度都以数字形式呈现)

同时,我认为为c++ ABI选择一种类似于c++的人类可读格式没有任何好处。这东西应该是为机器优化的。为什么你要让它对机器不那么理想,而让它对人类更理想呢?而且很可能在做后者的时候失败了。

你说你的编译器不发出"原始符号"。