Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does '_GLOBAL__sub_I_' mean in nm output?

While I was trying to resolve a problem in static linking, I encounter a couple of _GLOBAL__sub_I_ prefixes in front of symbol names. It appears in that form although I used nm --demangle(-C).

I stumbled upon this answer (How to find global static initializations). Looking at my source code, it indeed looks like initialization of a global static variable.

What I'm wondering is, where can I more information on __sub_ and other mangled names, like __cxxabiv1?

like image 870
CremeBaldEagle Avatar asked Jul 29 '15 04:07

CremeBaldEagle


People also ask

What does the output of NM mean?

The nm commands provides information on the symbols being used in an object file or executable file. The default information that the 'nm' command provides is : Virtual address of the symbol. A character which depicts the symbol type.


2 Answers

To prevent link rot i will answer here, although it is Chris Britt who should be credited with finding the information in the first place (see comments to the question).

If we look at "cxxabi.h File Reference" (2013) we see that the header defines two namespaces: __gnu_cxx and abi. So this is the header we are looking for "cxxabi.h File Reference" (2019) states that it was generated in 2009 and is almost identical, except that there is only abi namespace that is mentioned.

The difference is superficial, the header code itself defines the namespace __cxxabiv1 and then sets namespace abi = __cxxabiv1; so we can be sure that this header is still what we are looking for.

The following is declared in the header:

typedef __cxa_cdtor_return_type (*__cxa_cdtor_type)(void *);

int __cxxabiv1::__cxa_atexit (void(*)(void *), void *, void *) throw ();
void __cxxabiv1::__cxa_bad_cast ();
void __cxxabiv1::__cxa_bad_typeid ();
std::type_info * __cxxabiv1::__cxa_current_exception_type ();
char * __cxxabiv1::__cxa_demangle (const char *__mangled_name, char *__output_buffer, size_t *__length, int *__status);
int __cxxabiv1::__cxa_finalize (void *);
void __cxxabiv1::__cxa_guard_abort (__guard *);
int __cxxabiv1::__cxa_guard_acquire (__guard *);
void __cxxabiv1::__cxa_guard_release (__guard *);
void __cxxabiv1::__cxa_pure_virtual (void);
__cxa_vec_ctor_return_type __cxxabiv1::__cxa_vec_cctor (void *dest_array, void *src_array, size_t element_count, size_t element_size, __cxa_cdtor_return_type(*constructor)(void *, void *), __cxa_cdtor_type destructor);
void __cxxabiv1::__cxa_vec_cleanup (void *__array_address, size_t __element_count, size_t __element_size, __cxa_cdtor_type destructor);
__cxa_vec_ctor_return_type __cxxabiv1::__cxa_vec_ctor (void *__array_address, size_t __element_count, size_t __element_size, __cxa_cdtor_type constructor, __cxa_cdtor_type destructor);
void __cxxabiv1::__cxa_vec_delete (void *__array_address, size_t __element_size, size_t __padding_size, __cxa_cdtor_type destructor);
void __cxxabiv1::__cxa_vec_delete2 (void *__array_address, size_t __element_size, size_t __padding_size, __cxa_cdtor_type destructor, void(*__dealloc)(void *));
void __cxxabiv1::__cxa_vec_delete3 (void *__array_address, size_t __element_size, size_t __padding_size, __cxa_cdtor_type destructor, void(*__dealloc)(void *, size_t));
void __cxxabiv1::__cxa_vec_dtor (void *__array_address, size_t __element_count, size_t __element_size, __cxa_cdtor_type destructor);
void * __cxxabiv1::__cxa_vec_new (size_t __element_count, size_t __element_size, size_t __padding_size, __cxa_cdtor_type constructor, __cxa_cdtor_type destructor);
void * __cxxabiv1::__cxa_vec_new2 (size_t __element_count, size_t __element_size, size_t __padding_size, __cxa_cdtor_type constructor, __cxa_cdtor_type destructor, void *(*__alloc)(size_t), void(*__dealloc)(void *));
void * __cxxabiv1::__cxa_vec_new3 (size_t __element_count, size_t __element_size, size_t __padding_size, __cxa_cdtor_type constructor, __cxa_cdtor_type destructor, void *(*__alloc)(size_t), void(*__dealloc)(void *, size_t));
void * __cxxabiv1::__dynamic_cast (const void *__src_ptr, const __class_type_info *__src_type, const __class_type_info *__dst_type, ptrdiff_t __src2dst);

class __cxxabiv1::__fundamental_type_info : public std::type_info;
class __enum_type_info : public std::type_info;
class __pointer_type_info : public __pbase_type_info;
class __class_type_info : public std::type_info;
class __pointer_to_member_type_info : public __pbase_type_info;
class __base_class_type_info;
class __si_class_type_info : public __class_type_info;
class __vmi_class_type_info : public __class_type_info;

The header also includes:

#include <bits/cxxabi_tweaks.h>
#include <cxxabi-forced.h>

So it may be useful to take a look at them.

like image 143
v010dya Avatar answered Sep 20 '22 18:09

v010dya


I was getting a _GLOBAL__sub_I_ prefix in my symbols that I needed to get rid of.

Then found this: https://llvm.org/docs/FAQ.html:

What is this llvm.global_ctors and _GLOBAL__I_a... stuff that happens when I #include <iostream>?

If you #include the <iostream> header into a C++ translation unit, the file will probably use the std::cin/std::cout/… global objects. However, C++ does not guarantee an order of initialization between static objects in different translation units, so if a static ctor/dtor in your .cpp file used std::cout, for example, the object would not necessarily be automatically initialized before your use.

To make std::cout and friends work correctly in these scenarios, the STL that we use declares a static object that gets created in every translation unit that includes <iostream>. This object has a static constructor and destructor that initializes and destroys the global iostream objects before they could possibly be used in the file. The code that you see in the .ll file corresponds to the constructor and destructor registration code.

I moved my function into a translation unit without <fstream>, and the symbol is now exported without _GLOBAL__sub_I_.

like image 28
Victor Sergienko Avatar answered Sep 19 '22 18:09

Victor Sergienko