Linker. How could symbol be defined and undefined simultaneously? - c++

$ nm --demangle /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/libsupc++.a | grep "__cxxabiv1::__class_type_info::~__class_type_info"
gives following output:
0000000000000000 T __cxxabiv1::__class_type_info::~__class_type_info()
0000000000000000 T __cxxabiv1::__class_type_info::~__class_type_info()
0000000000000000 T __cxxabiv1::__class_type_info::~__class_type_info()
U __cxxabiv1::__class_type_info::~__class_type_info()
U __cxxabiv1::__class_type_info::~__class_type_info()
So, how to interpret this output?
Here is multiple definitions of the symbol (three T's) - how it could be? Why linker produced such library with violated ODR? What is the purpose? And why all of them have the same (and strange) address (0000000000000000)?
How the same symbol could be both defined (T) and undefined (U) simultaneously?

A static library (archive file, .a) is essentially a collection of individual .o files (plus some indexing information so the linker can find the .o files it needs). Some of those undefined symbols are in a different object than the one that defines them. If you look at the full output of nm this becomes clear. (Or use the -o flag to nm.)
The reason you have multiple defined symbols is that demangle isn't a 1-to-1 operation. In my copy of libsupc++, those three definitions are:
0000000000000000 T _ZN10__cxxabiv117__class_type_infoD0Ev
0000000000000000 T _ZN10__cxxabiv117__class_type_infoD1Ev
0000000000000000 T _ZN10__cxxabiv117__class_type_infoD2Ev
Why are there several symbols which all demangle to the destructor? They're destructors for different situations. gcc uses the Itanium ABI for C++, whose name mangling rules are described here.

Related

libgcc linker error: hidden symbol __aarch64_swp1_acq_rel in libgcc.a is referenced by DSO

I am trying to link a shared library I have no control on. This library has an undefined symbol (nm output):
U __aarch64_swp1_acq_rel
Which seems to be defined in libgcc.a:
[user#fedora ~]$ nm -a /usr/lib/gcc/aarch64-redhat-linux/12/libgcc.a | grep swp1_acq_rel
0000000000000000 T __aarch64_swp1_acq_rel
[user#fedora ~]$ objdump -t /usr/lib/gcc/aarch64-redhat-linux/12/libgcc.a | grep swp1_acq_rel
0000000000000000 g F .text 000000000000002c .hidden __aarch64_swp1_acq_rel
But whenever I try to link, I get the error in the title of this question. I understand that this symbol is hidden for dynamic linking (please confirm if I am wrong). So my question is what is the right approach to link against this libgcc symbol when the shared library I am using (and linking against) does not define it.
I expected that it would be possible to resolve this symbol with the libgcc.a in my system. Why is it hidden?
Compile it with cflags "-mno-outline-atomics" can solve my problem.
GCC 10.0 enables calls to out-of-line helpers to implement atomic operations.
You can view the compile code to see the differences:
https://godbolt.org/z/z8W7z1cqx

Where is the source code for `cout` defined? [duplicate]

When I try to see definition of cout, I land to iostream file where it is declared as,
extern _CRTDATA2 ostream cout;
So where it is defined? Because extern is just declaration and not definition.
Global symbols are defined in a run-time library that you link with your applications. For example, in gcc you pass the compiler option -lstdc++ that will link your application with the libstdc++.a library. That is where all such symbols reside.
Though, this is specific to your compiler/run-time library version and will vary. Microsoft Visual C++ may behave differently but the idea is the same: the symbols are inside the precompiled libraries that are delivered with your C++ compiler.
With GNU you can type:
nm -g libstdc++.a
to see the symbols inside the library. The output may look like this (among lots of other lines):
ios_init.o:
U _ZSt3cin
globals_io.o:
0000000000000000 D _ZSt3cin
0000000000000000 D _ZSt4cerr
0000000000000000 D _ZSt4clog
0000000000000000 D _ZSt4cout
0000000000000000 D _ZSt4wcin
0000000000000000 D _ZSt5wcerr
0000000000000000 D _ZSt5wclog
0000000000000000 D _ZSt5wcout

What is _ZStL8__ioinit symbol is for in a c++ symbol table?

When I use nm command to extract the symbol of my executable, I see there are many symbols of the type b (that is for BSS) as _ZStL8__ioinit. Also, on using c++filt to see the demangled symbol, I get the following:
~ c++filt _ZStL8__ioinit
~ std::__ioinit
What are these symbols for? and Why my code has more than one?
Any lead would be appreciated. Thanks!

cout is declared in iostream, but where it is defined?

When I try to see definition of cout, I land to iostream file where it is declared as,
extern _CRTDATA2 ostream cout;
So where it is defined? Because extern is just declaration and not definition.
Global symbols are defined in a run-time library that you link with your applications. For example, in gcc you pass the compiler option -lstdc++ that will link your application with the libstdc++.a library. That is where all such symbols reside.
Though, this is specific to your compiler/run-time library version and will vary. Microsoft Visual C++ may behave differently but the idea is the same: the symbols are inside the precompiled libraries that are delivered with your C++ compiler.
With GNU you can type:
nm -g libstdc++.a
to see the symbols inside the library. The output may look like this (among lots of other lines):
ios_init.o:
U _ZSt3cin
globals_io.o:
0000000000000000 D _ZSt3cin
0000000000000000 D _ZSt4cerr
0000000000000000 D _ZSt4clog
0000000000000000 D _ZSt4cout
0000000000000000 D _ZSt4wcin
0000000000000000 D _ZSt5wcerr
0000000000000000 D _ZSt5wclog
0000000000000000 D _ZSt5wcout

How can I inspect a static library to see if the debug symbols are being exported?

I have a static library I'm building in debug mode, but when I step into it I still get disassembly. I want to know how to use nm or another tool to ensure that the debug symbols are not being stripped.
You might use nm's option --debug-syms, to let nm also list debugger symbols (if any) for the object packed into a library.
For debugger symbols the second column indicates N.
Example (assumes the object example.o to be in the library)
nm --debug-syms libexample.a
Output (excerpt):
example.o:
0000000000000000 b .bss
0000000000000000 n .comment
0000000000000000 d .data
0000000000000000 N .debug_abbrev
0000000000000000 N .debug_aranges
0000000000000000 N .debug_info
0000000000000000 N .debug_line
0000000000000000 N .debug_loc
0000000000000000 N .debug_pubnames
0000000000000000 N .debug_str
0000000000000000 r .eh_frame
0000000000000000 n .note.GNU-stack
0000000000000000 r .rodata
0000000000000000 t .text
...
For more on this please see man nm.
You can use the file command, available for many OSes, including Windows via Cygwin.
If it says 'not stripped' it means it has the debug info present.
As a side note, for static libs use ar to extract the .o files & use file on them directly.
You can use strip -S libXX.a to check if your static library size has been reduce. The static library size will not change if it's not include debugging symbols.
It is works on Mac OS to check static library generated by Xcode.
Linux and Unix strip command
Download Dependencywalker for your OS
It will detect if your dll has debug symbols. If you see "Invalid" under "Symbols", it means debug symbols have been stripped off. Valid values are : PDB, CV, DBG, etc.