【问题标题】:Why doesn't g++ generate "raw" symbols?为什么 g++ 不生成“原始”符号?
【发布时间】:2015-11-02 12:48:05
【问题描述】:

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

使用dlsym,我们可以加载任意字符串,而C++ mangles names that include @ in the ABI.

我的问题是:可以使用任意字符串吗? dlsym 上的文档似乎没有提及任何内容。

Another question 出现似乎暗示完全有可能具有任意以空值结尾的符号。这要求我提出以下问题:

为什么 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)\0

相反,它被编译到 - 在我的 64 位机器上,使用 g++ 4.9.2 -

0000000000000000 T _ZN4test1A10myFunctionEi

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

【问题讨论】:

  • “原始函数签名”到底是什么意思?您是否希望这些符号具有类似 my_ns::my_class::create(int const *, bool) 的名称?
  • @lisyarus 这就是我的理解。这个例子很清楚。
  • @Quentin 是的,我明白了。谢谢。
  • @lisyarus:是的,甚至可能包含参数的名称,尽管这些并不重要。
  • 你见过重载函数时符号的样子吗?

标签: c++ name-mangling


【解决方案1】:

我确信做出这个决定是为了避免对预先存在的 C 链接器进行任何更改(甚至很可能源自 cfront)。通过发出具有相同字符集的符号,C 链接器习惯于您不必进行任何数量的更新,并且可以使用现成的链接器。

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

最后,由于您始终可以进行解码(例如使用 gc++filt 之类的东西),因此使用全文表示似乎不值得。

附:您绝对不想在函数名称中包含参数名称:如果重命名参数会破坏 ABI,人们会不高兴。已经很难保持 ABI 兼容性了。

【讨论】:

  • 反正没有“参数名称”这样的东西。调用者可能有一个具有不同参数名称的声明,但它命名相同的函数。
【解决方案2】:

GCC 符合Itanium C++ ABI。如果您的问题是“为什么 Itanium C++ ABI 需要以这种方式修改名称?”那么答案可能是

  1. 因为它的设计者认为这是个好主意,并且
  2. 符号越短,目标文件越小,动态链接越快。

关于第二点,Ulrich Drepper 的文章How To Write Shared Libraries有一个很好的解释。

【讨论】:

    【解决方案3】:
    1. 由于链接器(包括操作系统的动态链接器)对导出名称的限制 - 字符集、长度。 very phenomenon of mangling 就是因为这个而出现的。
      • 推论:在不存在这些限制的媒体(使用自己的链接器的各种 VM:例如 .NET、Java)中,也不存在修改。
    2. 产生与其他不兼容的导出的每个编译器都必须使用不同的方案。因为链接器(静态或动态)不关心 ABI,所以它只关心标识符。

    【讨论】:

    • 1.我认为这太抽象了:什么“限制”? 2. 像“编译目标文件”或“破坏名称”那样产生导出?这一点对我来说没有意义。
    • 1.我补充说:“字符集,长度”。 2. 每个编译单元都有一组导出符号和导入符号。链接器获取这些并将它们匹配在一起。 IE。所有关于导出实体的 ABI 的信息都必须编码到导出的名称中。
    【解决方案4】:

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

    合法名称的通用正则表达式类似于[\w_](\w\d_)*

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

    所以链接仅限于在 C 中已经合法的内容。这不包括冒号、括号、& 符号、星号,以及您在纯文本中对 C++ 标识符进行编码所需的任何其他内容。

    【讨论】:

    • 不,我没有,考虑到我后来提到另一个 SO 问题,说可以使用任何以空字符结尾的字符串。
    • @BourgondAries:您链接到的答案是关于 ELF 规范 对此有何评论。我很确定ld 仍然可以处理字母、数字和下划线的组合...
    【解决方案5】:

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

    这种格式是:

    • 不是特定于程序员的;考虑到所有这些都是一样的,所以为什么要混淆人们:
      • int ::test::A::myFunction(const int)
      • int ::test::A::myFunction(int const)
      • int test::A::myFunction(int const)
      • int test :: A :: myFunction (int const)
      • 等等……
    • 明确
    • 简洁;没有参数名称或其他不必要的装饰
    • 更容易解析(注意每个组件的长度以数字形式出现)

    同时,我认为为 C++ ABI 选择一种人类可读的外观类似 C++ 格式没有任何好处。这些东西应该针对机器进行优化。你为什么要让它对机器不太理想,以使它对人类更优化?并且在这样做时可能会在后者失败。

    您说您的编译器不会发出“原始符号”。我认为它正是这样做的。

    【讨论】:

    • 在问题中我试图在问题中定义“原始”符号,因此使用引号。还编辑了签名,使其更像一个定义。另外,我不确定easier to parse 部分。每当我们链接时,我们都需要声明或通过ld.so。前者根据编译器修改名称,后者只是为我们获取符号。您能否详细说明您的意思以及为什么我的想法有误?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-30
    相关资源
    最近更新 更多