函数的返回类型是否属于错误名称? [英] Is the return type of a function part of the mangled name?

查看:119
本文介绍了函数的返回类型是否属于错误名称?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有两个具有相同参数类型和名称的函数(不在同一程序中):

Suppose I have two functions with the same parameter types and name (not in the same program):

std::string foo(int x) {
  return "hello"; 
}

int foo(int x) {
  return x;
}

编译后,它们的名称是否相同?

Will they have the same mangled name once compiled?

在C ++中,损坏的名称的返回类型部分是吗?

Is the the return type part of the mangled name in C++?

推荐答案

由于不规范处理方案,因此没有一个单一的答案.与实际答案最接近的事情是查看由最常见的整形方案生成的整形名称.据我所知,这些是按字母顺序排列的GCC和MSVC方案,所以...

As mangling schemes aren't standardised, there's no single answer to this question; the closest thing to an actual answer would be to look at mangled names generated by the most common mangling schemes. To my knowledge, those are the GCC and MSVC schemes, in alphabetical order, so...

要对此进行测试,我们可以使用一个简单的程序.

To test this, we can use a simple program.

#include <string>
#include <cstdlib>

std::string foo(int x) { return "hello"; }
//int         foo(int x) { return x; }

int main() {
    // Assuming executable file named "a.out".
    system("nm a.out");
}

编译并使用GCC或Clang运行,它将列出其中包含的符号.根据未注释的功能,结果将是:

Compile and run with GCC or Clang, and it'll list the symbols it contains. Depending on which of the functions is uncommented, the results will be:

// GCC:
// ----

std::string foo(int x) { return "hello"; } // _Z3fooB5cxx11i
                                             // foo[abi:cxx11](int)
int         foo(int x) { return x; }       // _Z3fooi
                                             // foo(int)

// Clang:
// ------

std::string foo(int x) { return "hello"; } // _Z3fooi
                                             // foo(int)
int         foo(int x) { return x; }       // _Z3fooi
                                             // foo(int)

GCC方案包含的信息相对较少,不包括返回类型:

The GCC scheme contains relatively little information, not including return types:

  • 符号类型:"_Z"代表功能".
  • 名称:3foo代表::foo.
  • 参数:i用于int.
  • Symbol type: _Z for "function".
  • Name: 3foo for ::foo.
  • Parameters: i for int.

但是,尽管如此,它们在使用GCC(而不是Clang)进行编译时有所不同,因为GCC表示std::string版本使用cxx11 ABI.

Despite this, however, they are different when compiled with GCC (but not with Clang), because GCC indicates that the std::string version uses the cxx11 ABI.

请注意,它仍会跟踪返回类型,并确保签名匹配.它只是不使用函数的错误名称来这样做.

Note that it does still keep track of the return type, and make sure signatures match; it just doesn't use the function's mangled name to do so.

要对此进行测试,我们可以使用一个简单的程序,如上所述.

To test this, we can use a simple program, as above.

#include <string>
#include <cstdlib>
    
std::string foo(int x) { return "hello"; }
//int         foo(int x) { return x; }
    
int main() {
    // Assuming object file named "a.obj".
    // Pipe to file, because there are a lot of symbols when <string> is included.
    system("dumpbin/symbols a.obj > a.txt");
}

编译并使用Visual Studio运行,a.txt将列出其中包含的符号.根据未注释的功能,结果将是:

Compile and run with Visual Studio, and a.txt will list the symbols it contains. Depending on which of the functions is uncommented, the results will be:

std::string foo(int x) { return "hello"; }
  // ?foo@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@H@Z
  // class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl foo(int)
int         foo(int x) { return x; }
  // ?foo@@YAHH@Z
  // int __cdecl foo(int)

MSVC方案包含整个声明,包括未明确指定的内容:

The MSVC scheme contains the entire declaration, including things that weren't explicitly specified:

  • 名称:foo@表示::foo,后跟@终止.
  • 符号类型:以@结尾的名称之后的所有内容.
  • 类型和成员状态:Y用于非成员功能".
  • 呼叫约定:A表示__cdecl.
  • 返回类型:
    • H表示int.
    • ?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@(后跟@终止),表示std::basic_string<char, std::char_traits<char>, std::allocator<char>>(简称std::string).
    • Name: foo@ for ::foo, followed by @ to terminate.
    • Symbol type: Everything after the name-terminating @.
    • Type and member status: Y for "non-member function".
    • Calling convention: A for __cdecl.
    • Return type:
      • H for int.
      • ?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@ (followed by @ to terminate) for std::basic_string<char, std::char_traits<char>, std::allocator<char>> (std::string for short).

      如果在每个编译单元中声明都不相同,这将使它发怒.

      This allows it to whine at you if declarations aren't identical across every compilation unit.

      通常,大多数编译器在分别以* nix或Windows为目标时将使用这些方案之一(或有时是其变体),但这不能保证.例如...

      Generally, most compilers will use one of those schemes (or sometimes a variation thereof) when targeting *nix or Windows, respectively, but this isn't guaranteed. For example...

      • 据我所知,Clang将对* nix使用GCC方案,对于Windows将使用MSVC方案.
      • Intel C ++在Linux和Mac上使用GCC方案,在Windows上使用MSVC方案(有一些细微变化).
      • Borland和Watcom编译器都有自己的方案.
      • Symantec和Digital Mars编译器通常使用MSVC方案,但有一些小的更改.
      • 旧版本的GCC和许多UNIX工具使用cfront修改方案的修改版本.
      • 依此类推...

      其他编译器使用的方案要感谢 Agner Fog的PDF ./sup>

      检查生成的符号,很明显,GCC的篡改方案未提供与MSVC相同的针对Machiavelli的保护.请考虑以下内容:

      Examining the generated symbols, it becomes apparent that GCC's mangling scheme doesn't provide the same level of protection against Machiavelli as MSVC's. Consider the following:

      // foo.cpp
      #include <string>
      
      // Simple wrapper class, to avoid encoding `cxx11 ABI` into the GCC name.
      class MyString {
          std::string data;
      
        public:
          MyString(const char* const d) : data(d) {}
      
          operator std::string() { return data; }
      };
      
      // Evil.
      MyString foo(int i) { return "hello"; }
      
      // -----
      
      // main.cpp
      #include <iostream>
      
      // Evil.
      int foo(int);
      
      int main() {
          std::cout << foo(3) << '\n';
      }
      

      如果我们分别编译每个源文件,则尝试将目标文件链接在一起...

      If we compile each source file separately, then attempt to link the object files together...

      • GCC:MyString,由于不是cxx11 ABI的一部分,导致MyString foo(int)int foo(int)一样被粉碎为_Z3fooi.这样就可以链接目标文件,并生成可执行文件.尝试运行它会导致段错误.
      • MSVC:链接器将查找?foo@@YAHH@Z;否则,链接器将查找?foo@@YAHH@Z.因为我们改为提供?foo@@YA?AVMyString@@H@Z,所以链接将失败.
      • GCC: MyString, due to not being part of the cxx11 ABI, causes MyString foo(int) to be mangled as _Z3fooi, just like int foo(int). This allows the object files to be linked, and an executable is produced. Attempting to run it causes a segfault.
      • MSVC: The linker will look for ?foo@@YAHH@Z; as we instead supplied ?foo@@YA?AVMyString@@H@Z, linking will fail.

      考虑到这一点,即使不能仅根据返回类型的不同而重载函数,包含返回类型的处理方案也更安全.

      Considering this, a mangling scheme that includes the return type is safer, even though functions can't be overloaded solely on differences in return type.

      这篇关于函数的返回类型是否属于错误名称?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆