Trying to make the ta-lib library (ta-lib-0.4.0-src.tar.gz) I get the following error:
/home/me/ta-lib/src/.libs/libta_lib.so: undefined reference to `sinh'
/home/me/ta-lib/src/.libs/libta_lib.so: undefined reference to `sincos'
/home/me/ta-lib/src/.libs/libta_lib.so: undefined reference to `ceil'
...
for a large number of maths functions.
The failing command looks like this:
gcc -g -O2 -o .libs/ta_regtest (... .o files) -L/home/me/ta-lib/src \
/home/me/ta-lib/src/.libs/libta_lib.so -lm -lpthread -ldl
The offending library (ta_lib) looks like this:
objdump -TC libta_lib.so | grep " D \*UND\*"
0000000000000000 D *UND* 0000000000000000 sinh
0000000000000000 D *UND* 0000000000000000 sincos
0000000000000000 D *UND* 0000000000000000 ceil
...
For the same maths functions (the grep excludes defined functions and those that have a "w" (presumably weak) flag)
A map lists the libraries included, among them:
LOAD /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libm.so
and a list of the symbols (objdump -TC) defined in libm.so includes:
000000000001a320 w iD .text 0000000000000020 GLIBC_2.2.5 ceil
which was one of the undefined references (they are all there). I cannot determine the meaning of GLIBC_2.2.5.
Why is the loader not finding these functions?
My system looks like this:
$ uname -a
Linux mynode 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:31:23 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
Related
I'm trying to reduce the disk size of a big static library libIn.a that contains a lot (~3000) of small object files (.o), by combining all the object files into a single .o file; as far as I understand, this procedure is called "partial linking". The size reduction would be achieved by collapsing all the object sections (one per .o file) into a single one.
The problem I'm seeing is that the procedure I'm using does not preserve global-ness of the symbols included in the .o files included in libIn.a i.e., all symbols become local after the partial linking, and that causes "undefined symbol" errors downstream in the linking process.
As an example, that's how version.o object file (originally included in libIn.a, you can download version.o at https://github.com/giovanniberi93/problematic_object_file) looks like before performing partial linking:
└─ nm -Ca version.o
0000000000000000 T webrtc::LoadWebRTCVersionInRegister()
0000000000000024 s l_.str
0000000000000000 t ltmp0
0000000000000024 s ltmp1
So now the symbol webrtc::LoadWebRTCVersionInRegister() is global (T).
But when performing partial linking, the same symbol becomes local (t):
└─ ld -r version.o -o why_is_local.o
└─ nm -Ca why_is_local.o
0000000000000024 s LC1
0000000000000000 t webrtc::LoadWebRTCVersionInRegister()
Things get even weirder: when trying to replicate the same scenario with a sample .o file, the global symbols are not converted into local symbols (!); e.g., with input C++ file:
int function1() {
return 1;
}
Its global symbol function1() is not converted into local symbol by performing partial linkage i.e., it stays global (T) before and after partial linking:
└─ clang -c file1.cc
└─ nm -Ca file1.o
0000000000000000 T function1()
0000000000000000 t ltmp0
0000000000000008 s ltmp1
└─ ld -r file1.o -o relocated.o
└─ nm -Ca relocated.o
0000000000000000 T function1()
There must be some difference in version.o and file1.o that is causing the global symbols to become local, but I've not been able to pinpoint it. Any input would be greatly appreciated.
My env (MacOS 12.6, arm64):
└─ clang -v
Apple clang version 13.0.0 (clang-1300.0.29.3)
Target: arm64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Users/giober/Desktop/XCodes/13.1/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
└─ ld -v
#(#)PROGRAM:ld PROJECT:ld64-711
BUILD 18:11:19 Aug 3 2021
configured to support archs: armv6 armv7 armv7s arm64 arm64e arm64_32 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em
LTO support using: LLVM version 13.0.0, (clang-1300.0.29.3) (static support for 27, runtime is 27)
TAPI support using: Apple TAPI version 13.0.0 (tapi-1300.0.6.5)
└─ nm --version
Apple LLVM version 13.0.0 (clang-1300.0.29.3)
Optimized build.
Default target: arm64-apple-darwin21.6.0
Host CPU: vortex
The symbol in question is marked as "private external":
% nm -m version.o
0000000000000000 (__TEXT,__text) private external __ZN6webrtc27LoadWebRTCVersionInRegisterEv
0000000000000024 (__TEXT,__cstring) non-external l_.str
0000000000000000 (__TEXT,__text) non-external ltmp0
0000000000000024 (__TEXT,__cstring) non-external ltmp1
Not sure where that's coming from, but you can preserve this state with -keep_private_externs:
ld -keep_private_externs -r version.o -o output.o
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
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
$ 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.
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