¿El tipo de retorno de la función es parte de un nombre corrupto?

SOURCE 6924 palabras name-manglingc++

Preguntas frecuentes

Supongamos que tengo dos funciones con el mismo tipo de parámetro y nombre (no en el mismo programa):
std::string foo(int x) {
  return "hello"; 
}

int foo(int x) {
  return x;
}
¿Una vez compilados, tendrán el mismo nombre?
¿Es el tipo de retorno parte del nombre corrupto en C++?

La mejor solución

no hay una sola respuesta a esta pregunta porque el esquema de rotura no está estandarizado; Lo más cercano a la respuesta real es ver los nombres de corrupción generados por los esquemas de corrupción más comunes. Por lo que sé, estos son los esquemas GCC y MSVC, ordenados alfabéticamente, así que...

GCC:


Para probar esto, podemos usar un program a simple.
#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");
}
Compile y ejecute usando GCC o clang, que enumerará los símbolos que contiene. Dependiendo de la función no comentada, el resultado será:
// 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)
El esquema GCC contiene relativamente poca información, excluyendo los tipos de retorno:
  • tipo de símbolo: _Z significa "función".
  • nombre: 3foo significa ::foo.
  • Parámetro
  • : i de int.
  • Sin embargo, cuando se compilan con GCC (pero no con clang), son diferentes, ya que GCC indica que la versión std::string utiliza cxx11 ABI.
    Tenga en cuenta que todavía rastrea los tipos de retorno y asegura que las firmas coincidan; Simplemente no se implementa usando el nombre de la función.

    MSVC:


    Para probar esto, podemos utilizar un program a simple como se ha descrito anteriormente.
    #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");
    }
    
    Compilado y ejecutado usando Visual Studio, a.txt enumera los símbolos que contiene. Dependiendo de la función no comentada, el resultado será:
    std::string foo(int x) { return "hello"; }
      // [email protected]@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]
      // class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl foo(int)
    int         foo(int x) { return x; }
      // [email protected]@[email protected]
      // int __cdecl foo(int)
    
    El esquema MSVC contiene toda la Declaración, incluyendo lo que no se especifica explícitamente:
  • name: [email protected] represents ::foo, followed by @ Termination.
  • tipo de símbolo: todo después de que el nombre termine @.
  • type and Membership status: Y denotes "non - Membership Function".
  • Call Convention: A represents __cdecl.
  • tipo de retorno:
  • H de int.
  • [email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected] (seguido de @ terminación) significa std::basic_string<char, std::char_traits<char>, std::allocator<char>> (para abreviar std::string).
  • Lista de parámetros
  • : H de int (seguido de @ terminación).
  • descriptor de excepción: Z significa throw(...); Esta se omite del nombre requerido, a menos que sea otra cosa, probablemente porque MSVC lo ignoró.
  • Si la Declaración de cada unidad de compilación es diferente, puede quejarse ante usted.
    Por lo general, la mayoría de los compiladores utilizan uno de estos esquemas (y a veces sus variantes) Cuando se dirigen a * nix o Windows, respectivamente, pero esto no está garantizado. Por ejemplo...
    Por lo que sé,
  • clang usará el esquema GCC para * nix, o el esquema MSVC para Windows.
  • Intel C++ utiliza el esquema GCC en Linux y Mac, y el esquema MSVC en Windows (con algunos cambios menores).
  • Los compiladores
  • Borland y watcom tienen sus propios esquemas.
  • Los compiladores Symantec y digital Mars
  • suelen utilizar el esquema MSVC con sólo algunos cambios menores.
  • versiones antiguas de GCC y muchas herramientas UNIX utilizan versiones modificadas del esquema de gestión de cfront.
  • y así sucesivamente...
  • Todos los demás compiladores utilizan el esquema debido a Agner Fog's PDF.

    Nota:


    Al examinar los símbolos generados, es evidente que el esquema de daño de GCC no proporciona el mismo nivel de protección Maquiavelo que MSVC. Considere lo siguiente:
    // 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';
    }
    
    Si compilamos cada archivo fuente por separado e intentamos enlazar los archivos de destino juntos...
  • GCC: MyString, ya que no forma parte de cxx11 Abi, causa que MyString foo(int) sea dañado a _Z3fooi, al igual que int foo(int). Esto permite enlazar archivos de objetos y generar ejecutables. Un intento de ejecutarlo resulta en segfault.
  • MSVC: el linker buscará [email protected]@[email protected]; Debido a que proporcionamos [email protected]@[email protected]@[email protected], el enlace fallará.
  • Teniendo esto en cuenta, el esquema de corrupción que contiene el tipo de retorno es más seguro, incluso si la función no puede ser sobrecargada sólo debido a diferencias en el tipo de retorno.