C++0x thread static linking problem - c++

I am having some issues trying to statically link programs using c++0x thread features. Code looks this: (Compiler is gcc 4.6.1 on Debian x86_64 testing)
#include <iostream>
#include <thread>
static void foo() {
std::cout << "FOO BAR\n";
}
int main() {
std::thread t(foo);
t.join();
return 0;
}
I link it with:
g++ -static -pthread -o t-static t.cpp -std=c++0x
When I execute the program, I have the following error:
terminate called after throwing an instance of 'std::system_error'
what(): Operation not permitted
Aborted
GDB Debug output looks like this:
Debugger finished
Current directory is ~/testspace/thread/
GNU gdb (GDB) 7.2-debian
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/will/testspace/thread/t-static...done.
(gdb) list -
1 #include <iostream>
(gdb) b 1
Breakpoint 1 at 0x4007c8: file t.cpp, line 1.
(gdb) r
Starting program: /home/will/testspace/thread/t-static
terminate called after throwing an instance of 'std::system_error'
what(): Operation not permitted
Program received signal SIGABRT, Aborted.
0x00000000004a8e65 in raise ()
(gdb) bt
#0 0x00000000004a8e65 in raise ()
#1 0x000000000045df90 in abort ()
#2 0x000000000044570d in __gnu_cxx::__verbose_terminate_handler() ()
#3 0x0000000000442fb6 in __cxxabiv1::__terminate(void (*)()) ()
#4 0x0000000000442fe3 in std::terminate() ()
#5 0x0000000000443cbe in __cxa_throw ()
#6 0x0000000000401fe4 in std::__throw_system_error(int) ()
#7 0x00000000004057e7 in std::thread::_M_start_thread(std::shared_ptr<std::thread::_Impl_base>) ()
#8 0x0000000000400b18 in std::thread::thread<void (&)()> (this=0x7fffffffe540, __f=#0x4007c4) at /usr/include/c++/4.6/thread:135
#9 0x00000000004007f3 in main () at t.cpp:11
(gdb)
Update:
Linking with static libstdc++ could (possibly) make this error disappear, and the compiled C++0x programs can run on systems without gcc 4.6 libs:
g++ -static-libgcc -pthread -L.-o t thread.cpp -std=c++0x
But first, we should make a symbolic link to 'libstdc++.a' at current directory:
ln -s `g++ -print-file-name=libstdc++.a`
(Reference: http://www.trilithium.com/johan/2005/06/static-libstdc/)

you can use -u to resolve the problem (test in gcc version 4.6.3/(Ubuntu EGLIBC 2.15-0ubuntu10.4) 2.15 , gcc version 4.8.1/(Ubuntu EGLIBC 2.15-0ubuntu10.5~ppa1) 2.15)
-Wl,-u,pthread_cancel,-u,pthread_cond_broadcast,-u,pthread_cond_destroy,-u,pthread_cond_signal,-u,pthread_cond_wait,-u,pthread_create,-u,pthread_detach,-u,pthread_cond_signal,-u,pthread_equal,-u,pthread_join,-u,pthread_mutex_lock,-u,pthread_mutex_unlock,-u,pthread_once,-u,pthread_setcancelstate
1. reproduce the bug
g++ -g -O0 -static -std=c++11 t.cpp -lpthread
./a.out
terminate called after throwing an instance of 'std::system_error'
what(): Enable multithreading to use std::thread: Operation not permitted
Aborted (core dumped)
nm a.out | egrep "\bpthread_.*"
w pthread_cond_broadcast
w pthread_cond_destroy
w pthread_cond_signal
w pthread_cond_wait
w pthread_create
w pthread_detach
w pthread_equal
w pthread_join
w pthread_mutex_lock
w pthread_mutex_unlock
w pthread_once
w pthread_setcancelstate
2. resolve the bug
g++ -g -O0 -static -std=c++11 t.cpp -lpthread -Wl,-u,pthread_join,-u,pthread_equal
./a.out
FOO BAR
nm a.out | egrep "\bpthread_.*"
0000000000406320 T pthread_cancel
w pthread_cond_broadcast
w pthread_cond_destroy
w pthread_cond_signal
w pthread_cond_wait
0000000000404970 W pthread_create
w pthread_detach
00000000004033e0 T pthread_equal
00000000004061a0 T pthread_getspecific
0000000000403270 T pthread_join
0000000000406100 T pthread_key_create
0000000000406160 T pthread_key_delete
00000000004057b0 T pthread_mutex_lock
00000000004059c0 T pthread_mutex_trylock
0000000000406020 T pthread_mutex_unlock
00000000004063b0 T pthread_once
w pthread_setcancelstate
0000000000406220 T pthread_setspecific

For reasons exactly unknown to me (I consider this a bug) you can not use std::thread on gcc 4.6 when linking statically, since the function __ghtread_active_p() will be inlined as returning false (look at the assembly of _M_start_thread), causing this exception to be thrown. It might be that they require weak symbols for the pthread_create function there and when statically linking they are not there, but why they don't do it otherwise is beyond me (Note that the assembly later contains things like callq 0x0, there seems to be going something very wrong).
For now I personally use boost::threads since I am using boost anyways...

You should make sure you're linking against pthread library, otherwise you'll get the "Operation not permitted" message.
For instance, to compile your source code, I'd use this:
g++ -Wall -fexceptions -std=c++0x -g -c file.cpp -o file.o
Then linking with this:
g++ -o file file.o -lpthread
When doing it without object files, you could try something like this:
g++ -Wall -fexceptions -std=c++0x -g main.cpp -o file -lpthread
Remember to leave libraries at the end, since they'll be used on the linking process only.

My previous answer was deleted and I wrote detailed answer.
In common cases this issue happens due incomplete linking of the libpthread. I found information about this here https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52590
You can try link you app with the following flags:
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
Also you could look at this questions with the similar problem:
What is the correct link options to use std::thread in GCC under linux?
Starting a std::thread with static linking causes segmentation fault

Related

std::thread.join() crashes with trivial malloc wrap via ld --wrap=malloc [duplicate]

#include <iostream>
#include <map>
#include <thread>
#define SIZE 1024
#define AMOUNT 100000
#define THREADS 4
class A
{
private:
char a[SIZE];
};
void test()
{
std::cout << "test start\n";
std::map<int, A*> container;
for(int i=0; i<AMOUNT; i++)
{
A* a = new A();
std::pair<int, A*>p = std::make_pair(i, a);
container.insert(p);
}
std::cout << "test release\n";
for(int i=0; i<AMOUNT; i++)
{
auto iter = container.find(i);
delete iter->second;
container.erase(iter);
}
std::cout << "test end\n";
}
int main()
{
std::thread ts[THREADS];
for(int i=0; i<THREADS; i++)
{
ts[i] = std::thread(test);
}
for(std::thread& x: ts)
{
x.join();
}
return 0;
}
Above is a simple c++ code.
compile with: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3
ldd one, gots:
linux-vdso.so.1 => (0x00007ffebafce000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fb47352a000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fb473313000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb4730f4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb472d2a000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb472a22000)
/lib64/ld-linux-x86-64.so.2 (0x00005654c5112000)
run ./one, every thing is ok.
Then I try a static link: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3 -static
ldd one, gots:
not a dynamic executable
But when I run it, some thing goes wrong...
test start
Segmentation fault (core dumped)
re-compile with -g, and the gdb shows:
wang[00:35][~/test]$ gdb one
GNU gdb (Ubuntu 7.10-1ubuntu2) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from one...done.
(gdb) run
Starting program: /home/wang/test/one
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7ffa700 (LWP 3623)]
test start
[New Thread 0x7ffff77f8700 (LWP 3624)]
test start
[New Thread 0x7ffff6ff7700 (LWP 3625)]
test start
[New Thread 0x7ffff67f6700 (LWP 3626)]
test start
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb)
Why this ?
UPDATE
==============================
using boost::thread library (boost version: 1.60),
replace std::thread with boost::thread , and make a static link,
g++ -pthread -o one1 one.cpp -Wall -std=c++11 -O3 -I /opt/boost/include/ -L /opt/boost/lib/ -lboost_system -lboost_thread -static
no problem occurred!
confused...
First, the solution. This here will work:
Update: Since Ubuntu 18.04, you need to link also against librt (add -lrt):
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -lrt -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
(continue with original answer)
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
When you use -pthread, the compiler will already link against pthread (and depending on the platform, it does define extra macros like -D_REENTRANT, see this question for more details).
So if -pthread implies -lpthread, why do you need you specify -lpthread when you are linking statically? And what does Wl,--whole-archive do?
Understanding weak symbols
On Unix, the ELF file format is used, which has the concept of weak and strong symbols. To quote from the Wikipedia page:
By default, without any annotation, a symbol in an object file is strong. During linking, a strong symbol can override a weak symbol of the same name. In contrast, two strong symbols that share a name yield a link error during link-time.
There is a subtle difference when it comes to dynamic and static libraries. In static libraries, the linker will stop at the first symbol, even if it is a weak one, and stops looking for strong ones. To force it to look at all symbols (like it would have done for a dynamically linked library), ld supports the --whole-archive option.
To quote from man ld:
--whole-archive:
For each archive mentioned on the command line after the --whole-archive option, include every object file in the archive in the
link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a
shared library, forcing every object to be included in the resulting shared library. This option may be used more than once.
It goes on by explaining that from gcc, you have to pass the option as -Wl,--whole-archive:
Two notes when using this option from gcc: First, gcc doesn't know about this option, so you have to use -Wl,-whole-archive.
Second, don't forget to use -Wl,-no-whole-archive after your list of archives, because gcc will add its own list of archives to
your link and you may not want this flag to affect those as well.
And it explains how to turn it off, again:
--no-whole-archive:
Turn off the effect of the --whole-archive option for subsequent archive files.
Weak symbols in pthread and libstdc++
One of the use cases of weak symbols is to be able to swap out implementations with optimized ones. Another is to use stubs, which can later to replaced if necessary.
For example, fputc (conceptionally used by printf) is required by POSIX to be thread-safe and needs to be synchronized, which is costly. In a single-threaded environment, you do not want to pay the costs. An implementation could therefore implement the synchronization functions as empty stubs, and declare the functions as weak symbols.
Later, if a multi-threading library is linked (e.g., pthread), it becomes obvious that single-thread support is not intended. When linking the multi-threading library, the linker can then replace the stubs by the real synchronization functions (defined as strong symbols and implemented by the threading-library). On the other hand, if no multi-threading library is linked, the executable will use the stubs for the synchronization function.
glibc (providing fputc) and pthreads seem to use exactly this trick. For details, refer to this question about the usage of weak symbols in glibc. The example above is taken from this answer.
nm allows you to look at it in detail, which seems consistent with the cited answer above:
$ nm /usr/lib/libc.a 2>/dev/null | grep pthread_mutex_lock
w __pthread_mutex_lock
... (repeats)
"w" stands for "weak", so the statically linked libc library contains __pthread_mutex_lock as a weak symbol. The statically linked pthread library contains it as a strong symbol:
$ nm /usr/lib/libpthread.a 2>/dev/null | grep pthread_mutex_lock
U pthread_mutex_lock
pthread_mutex_lock.o:
00000000000006a0 T __pthread_mutex_lock
00000000000006a0 T pthread_mutex_lock
0000000000000000 t __pthread_mutex_lock_full
Back to the example program
By looking at the shared library dependencies of the dynamically linked executable, I get almost the same output of ldd on my machine:
$ ldd one
linux-vdso.so.1 (0x00007fff79d6d000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007fcaaeeb3000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007fcaaeb9b000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007fcaae983000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fcaae763000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fcaae3bb000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcaaf23b000)
Printing out the library calls with ltrace, leads to the following output:
$ ltrace -C ./one
std::ios_base::Init::Init()(0x563ab8df71b1, 0x7ffdc483cae8, 0x7ffdc483caf8, 160) = 0
__cxa_atexit(0x7fab3023bc20, 0x563ab8df71b1, 0x563ab8df7090, 6) = 0
operator new(unsigned long)(16, 0x7ffdc483cae8, 0x7ffdc483caf8, 192) = 0x563ab918bc20
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2f6a1fb0, 0, 0x800000) = 0x563ab918bd70
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2eea0fb0, 0, 0x800000) = 0x563ab918bec0
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
) = 0
operator new(unsigned long)(16, 0x7fab2e69ffb0, 0, 0x800000) = 0x563ab918c010
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
test start
) = 0
std::thread::join()(0x7ffdc483c9a0, 0x7fab2de9efb0, 0, 0x800000test start
test release
test release
test release
test release
test end
test end
test end
test end
) = 0
std::thread::join()(0x7ffdc483c9a8, 0x7fab2eea19c0, 0x7fab2f6a2700, 0) = 0
std::thread::join()(0x7ffdc483c9b0, 0x7fab2e6a09c0, 0x7fab2eea1700, 0) = 0
std::thread::join()(0x7ffdc483c9b8, 0x7fab2de9f9c0, 0x7fab2e6a0700, 0) = 0
+++ exited (status 0) +++
As an example, std::thread::join is called, which will most likely use pthread_join internally. That symbol can be found in the (dynamically linked) libraries listed in the ldd ouput, namely in libstdc++.so.6 and libpthread.so.0:
$ nm /usr/lib/libstdc++.so.6 | grep pthread_join
w pthread_join
$ nm /usr/lib/libpthread.so.0 | grep pthread_join
0000000000008280 T pthread_join
In the dynamically linked executable, the linker will replace weak symbols by strong symbols. In this example, we have to enforce the same semantic for the statically linked libraries. That is why -Wl,--whole-archive -lpthread -Wl,--no-whole-archive is needed.
Finding it out is a bit trial-and-error. At least, I found no clear documentation on that subject. I assume it is because static linking on Linux has become rather an edge case, whereas dynamic linking is often the canonical approach on how to use the libraries (for a comparison, see Static linking vs dynamic linking). The most extreme example that I have seen and personally struggled with a while to get it working is to link TBB statically.
Appendix: Workaround for Autotools
If you are using autotools as a build system, you need a workaround, as automake does not let you set options in the in LDADD. Unfortunately, you cannot write:
(Makefile.am)
mytarget_LDADD = -Wl,--whole-archive -lpthread -Wl,--no-whole-archive
As a workaround, you can avoid the check by defining the flags in configure.ac, and using them like this:
(configure.ac)
WL_WHOLE_ARCHIVE_HACK="-Wl,--whole-archive"
WL_NO_WHOLE_ARCHIVE_HACK="-Wl,--no-whole-archive"
AC_SUBST(WL_WHOLE_ARCHIVE_HACK)
AC_SUBST(WL_NO_WHOLE_ARCHIVE_HACK)
(Makefile.am)
mytarget_LDADD = #WL_WHOLE_ARCHIVE_HACK# -lpthread #WL_NO_WHOLE_ARCHIVE_HACK#
I had similar issue when linking a pre-built C++ .a archive that uses pthread. In my case I needed in addition to -Wl,--whole-archive -lpthread -Wl,--no-whole-archive also do -Wl,-u,... for each weak symbol.
My symptom was crashes at runtime and when using gdb to disassemble I could see that the crash was just after a callq 0x0 which seemed suspicious. Did some seaching and found that others had seen this with static pthread linking.
I figured out which symbols to force resolve by using nm and look for w symbols. After linking I could then see that the callq 0x0 instructions had been updated with various symbol addresses to pthread_mutex_lock etc.

Segmentation Fault while using Static Linking using C++ Threads [duplicate]

#include <iostream>
#include <map>
#include <thread>
#define SIZE 1024
#define AMOUNT 100000
#define THREADS 4
class A
{
private:
char a[SIZE];
};
void test()
{
std::cout << "test start\n";
std::map<int, A*> container;
for(int i=0; i<AMOUNT; i++)
{
A* a = new A();
std::pair<int, A*>p = std::make_pair(i, a);
container.insert(p);
}
std::cout << "test release\n";
for(int i=0; i<AMOUNT; i++)
{
auto iter = container.find(i);
delete iter->second;
container.erase(iter);
}
std::cout << "test end\n";
}
int main()
{
std::thread ts[THREADS];
for(int i=0; i<THREADS; i++)
{
ts[i] = std::thread(test);
}
for(std::thread& x: ts)
{
x.join();
}
return 0;
}
Above is a simple c++ code.
compile with: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3
ldd one, gots:
linux-vdso.so.1 => (0x00007ffebafce000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fb47352a000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fb473313000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb4730f4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb472d2a000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb472a22000)
/lib64/ld-linux-x86-64.so.2 (0x00005654c5112000)
run ./one, every thing is ok.
Then I try a static link: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3 -static
ldd one, gots:
not a dynamic executable
But when I run it, some thing goes wrong...
test start
Segmentation fault (core dumped)
re-compile with -g, and the gdb shows:
wang[00:35][~/test]$ gdb one
GNU gdb (Ubuntu 7.10-1ubuntu2) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from one...done.
(gdb) run
Starting program: /home/wang/test/one
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7ffa700 (LWP 3623)]
test start
[New Thread 0x7ffff77f8700 (LWP 3624)]
test start
[New Thread 0x7ffff6ff7700 (LWP 3625)]
test start
[New Thread 0x7ffff67f6700 (LWP 3626)]
test start
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb)
Why this ?
UPDATE
==============================
using boost::thread library (boost version: 1.60),
replace std::thread with boost::thread , and make a static link,
g++ -pthread -o one1 one.cpp -Wall -std=c++11 -O3 -I /opt/boost/include/ -L /opt/boost/lib/ -lboost_system -lboost_thread -static
no problem occurred!
confused...
First, the solution. This here will work:
Update: Since Ubuntu 18.04, you need to link also against librt (add -lrt):
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -lrt -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
(continue with original answer)
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
When you use -pthread, the compiler will already link against pthread (and depending on the platform, it does define extra macros like -D_REENTRANT, see this question for more details).
So if -pthread implies -lpthread, why do you need you specify -lpthread when you are linking statically? And what does Wl,--whole-archive do?
Understanding weak symbols
On Unix, the ELF file format is used, which has the concept of weak and strong symbols. To quote from the Wikipedia page:
By default, without any annotation, a symbol in an object file is strong. During linking, a strong symbol can override a weak symbol of the same name. In contrast, two strong symbols that share a name yield a link error during link-time.
There is a subtle difference when it comes to dynamic and static libraries. In static libraries, the linker will stop at the first symbol, even if it is a weak one, and stops looking for strong ones. To force it to look at all symbols (like it would have done for a dynamically linked library), ld supports the --whole-archive option.
To quote from man ld:
--whole-archive:
For each archive mentioned on the command line after the --whole-archive option, include every object file in the archive in the
link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a
shared library, forcing every object to be included in the resulting shared library. This option may be used more than once.
It goes on by explaining that from gcc, you have to pass the option as -Wl,--whole-archive:
Two notes when using this option from gcc: First, gcc doesn't know about this option, so you have to use -Wl,-whole-archive.
Second, don't forget to use -Wl,-no-whole-archive after your list of archives, because gcc will add its own list of archives to
your link and you may not want this flag to affect those as well.
And it explains how to turn it off, again:
--no-whole-archive:
Turn off the effect of the --whole-archive option for subsequent archive files.
Weak symbols in pthread and libstdc++
One of the use cases of weak symbols is to be able to swap out implementations with optimized ones. Another is to use stubs, which can later to replaced if necessary.
For example, fputc (conceptionally used by printf) is required by POSIX to be thread-safe and needs to be synchronized, which is costly. In a single-threaded environment, you do not want to pay the costs. An implementation could therefore implement the synchronization functions as empty stubs, and declare the functions as weak symbols.
Later, if a multi-threading library is linked (e.g., pthread), it becomes obvious that single-thread support is not intended. When linking the multi-threading library, the linker can then replace the stubs by the real synchronization functions (defined as strong symbols and implemented by the threading-library). On the other hand, if no multi-threading library is linked, the executable will use the stubs for the synchronization function.
glibc (providing fputc) and pthreads seem to use exactly this trick. For details, refer to this question about the usage of weak symbols in glibc. The example above is taken from this answer.
nm allows you to look at it in detail, which seems consistent with the cited answer above:
$ nm /usr/lib/libc.a 2>/dev/null | grep pthread_mutex_lock
w __pthread_mutex_lock
... (repeats)
"w" stands for "weak", so the statically linked libc library contains __pthread_mutex_lock as a weak symbol. The statically linked pthread library contains it as a strong symbol:
$ nm /usr/lib/libpthread.a 2>/dev/null | grep pthread_mutex_lock
U pthread_mutex_lock
pthread_mutex_lock.o:
00000000000006a0 T __pthread_mutex_lock
00000000000006a0 T pthread_mutex_lock
0000000000000000 t __pthread_mutex_lock_full
Back to the example program
By looking at the shared library dependencies of the dynamically linked executable, I get almost the same output of ldd on my machine:
$ ldd one
linux-vdso.so.1 (0x00007fff79d6d000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007fcaaeeb3000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007fcaaeb9b000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007fcaae983000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fcaae763000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fcaae3bb000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcaaf23b000)
Printing out the library calls with ltrace, leads to the following output:
$ ltrace -C ./one
std::ios_base::Init::Init()(0x563ab8df71b1, 0x7ffdc483cae8, 0x7ffdc483caf8, 160) = 0
__cxa_atexit(0x7fab3023bc20, 0x563ab8df71b1, 0x563ab8df7090, 6) = 0
operator new(unsigned long)(16, 0x7ffdc483cae8, 0x7ffdc483caf8, 192) = 0x563ab918bc20
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2f6a1fb0, 0, 0x800000) = 0x563ab918bd70
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2eea0fb0, 0, 0x800000) = 0x563ab918bec0
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
) = 0
operator new(unsigned long)(16, 0x7fab2e69ffb0, 0, 0x800000) = 0x563ab918c010
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
test start
) = 0
std::thread::join()(0x7ffdc483c9a0, 0x7fab2de9efb0, 0, 0x800000test start
test release
test release
test release
test release
test end
test end
test end
test end
) = 0
std::thread::join()(0x7ffdc483c9a8, 0x7fab2eea19c0, 0x7fab2f6a2700, 0) = 0
std::thread::join()(0x7ffdc483c9b0, 0x7fab2e6a09c0, 0x7fab2eea1700, 0) = 0
std::thread::join()(0x7ffdc483c9b8, 0x7fab2de9f9c0, 0x7fab2e6a0700, 0) = 0
+++ exited (status 0) +++
As an example, std::thread::join is called, which will most likely use pthread_join internally. That symbol can be found in the (dynamically linked) libraries listed in the ldd ouput, namely in libstdc++.so.6 and libpthread.so.0:
$ nm /usr/lib/libstdc++.so.6 | grep pthread_join
w pthread_join
$ nm /usr/lib/libpthread.so.0 | grep pthread_join
0000000000008280 T pthread_join
In the dynamically linked executable, the linker will replace weak symbols by strong symbols. In this example, we have to enforce the same semantic for the statically linked libraries. That is why -Wl,--whole-archive -lpthread -Wl,--no-whole-archive is needed.
Finding it out is a bit trial-and-error. At least, I found no clear documentation on that subject. I assume it is because static linking on Linux has become rather an edge case, whereas dynamic linking is often the canonical approach on how to use the libraries (for a comparison, see Static linking vs dynamic linking). The most extreme example that I have seen and personally struggled with a while to get it working is to link TBB statically.
Appendix: Workaround for Autotools
If you are using autotools as a build system, you need a workaround, as automake does not let you set options in the in LDADD. Unfortunately, you cannot write:
(Makefile.am)
mytarget_LDADD = -Wl,--whole-archive -lpthread -Wl,--no-whole-archive
As a workaround, you can avoid the check by defining the flags in configure.ac, and using them like this:
(configure.ac)
WL_WHOLE_ARCHIVE_HACK="-Wl,--whole-archive"
WL_NO_WHOLE_ARCHIVE_HACK="-Wl,--no-whole-archive"
AC_SUBST(WL_WHOLE_ARCHIVE_HACK)
AC_SUBST(WL_NO_WHOLE_ARCHIVE_HACK)
(Makefile.am)
mytarget_LDADD = #WL_WHOLE_ARCHIVE_HACK# -lpthread #WL_NO_WHOLE_ARCHIVE_HACK#
I had similar issue when linking a pre-built C++ .a archive that uses pthread. In my case I needed in addition to -Wl,--whole-archive -lpthread -Wl,--no-whole-archive also do -Wl,-u,... for each weak symbol.
My symptom was crashes at runtime and when using gdb to disassemble I could see that the crash was just after a callq 0x0 which seemed suspicious. Did some seaching and found that others had seen this with static pthread linking.
I figured out which symbols to force resolve by using nm and look for w symbols. After linking I could then see that the callq 0x0 instructions had been updated with various symbol addresses to pthread_mutex_lock etc.

c++ using condition_variable as class member for a class that spawns threads [duplicate]

#include <iostream>
#include <map>
#include <thread>
#define SIZE 1024
#define AMOUNT 100000
#define THREADS 4
class A
{
private:
char a[SIZE];
};
void test()
{
std::cout << "test start\n";
std::map<int, A*> container;
for(int i=0; i<AMOUNT; i++)
{
A* a = new A();
std::pair<int, A*>p = std::make_pair(i, a);
container.insert(p);
}
std::cout << "test release\n";
for(int i=0; i<AMOUNT; i++)
{
auto iter = container.find(i);
delete iter->second;
container.erase(iter);
}
std::cout << "test end\n";
}
int main()
{
std::thread ts[THREADS];
for(int i=0; i<THREADS; i++)
{
ts[i] = std::thread(test);
}
for(std::thread& x: ts)
{
x.join();
}
return 0;
}
Above is a simple c++ code.
compile with: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3
ldd one, gots:
linux-vdso.so.1 => (0x00007ffebafce000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fb47352a000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fb473313000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb4730f4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb472d2a000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb472a22000)
/lib64/ld-linux-x86-64.so.2 (0x00005654c5112000)
run ./one, every thing is ok.
Then I try a static link: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3 -static
ldd one, gots:
not a dynamic executable
But when I run it, some thing goes wrong...
test start
Segmentation fault (core dumped)
re-compile with -g, and the gdb shows:
wang[00:35][~/test]$ gdb one
GNU gdb (Ubuntu 7.10-1ubuntu2) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from one...done.
(gdb) run
Starting program: /home/wang/test/one
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7ffa700 (LWP 3623)]
test start
[New Thread 0x7ffff77f8700 (LWP 3624)]
test start
[New Thread 0x7ffff6ff7700 (LWP 3625)]
test start
[New Thread 0x7ffff67f6700 (LWP 3626)]
test start
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb)
Why this ?
UPDATE
==============================
using boost::thread library (boost version: 1.60),
replace std::thread with boost::thread , and make a static link,
g++ -pthread -o one1 one.cpp -Wall -std=c++11 -O3 -I /opt/boost/include/ -L /opt/boost/lib/ -lboost_system -lboost_thread -static
no problem occurred!
confused...
First, the solution. This here will work:
Update: Since Ubuntu 18.04, you need to link also against librt (add -lrt):
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -lrt -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
(continue with original answer)
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
When you use -pthread, the compiler will already link against pthread (and depending on the platform, it does define extra macros like -D_REENTRANT, see this question for more details).
So if -pthread implies -lpthread, why do you need you specify -lpthread when you are linking statically? And what does Wl,--whole-archive do?
Understanding weak symbols
On Unix, the ELF file format is used, which has the concept of weak and strong symbols. To quote from the Wikipedia page:
By default, without any annotation, a symbol in an object file is strong. During linking, a strong symbol can override a weak symbol of the same name. In contrast, two strong symbols that share a name yield a link error during link-time.
There is a subtle difference when it comes to dynamic and static libraries. In static libraries, the linker will stop at the first symbol, even if it is a weak one, and stops looking for strong ones. To force it to look at all symbols (like it would have done for a dynamically linked library), ld supports the --whole-archive option.
To quote from man ld:
--whole-archive:
For each archive mentioned on the command line after the --whole-archive option, include every object file in the archive in the
link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a
shared library, forcing every object to be included in the resulting shared library. This option may be used more than once.
It goes on by explaining that from gcc, you have to pass the option as -Wl,--whole-archive:
Two notes when using this option from gcc: First, gcc doesn't know about this option, so you have to use -Wl,-whole-archive.
Second, don't forget to use -Wl,-no-whole-archive after your list of archives, because gcc will add its own list of archives to
your link and you may not want this flag to affect those as well.
And it explains how to turn it off, again:
--no-whole-archive:
Turn off the effect of the --whole-archive option for subsequent archive files.
Weak symbols in pthread and libstdc++
One of the use cases of weak symbols is to be able to swap out implementations with optimized ones. Another is to use stubs, which can later to replaced if necessary.
For example, fputc (conceptionally used by printf) is required by POSIX to be thread-safe and needs to be synchronized, which is costly. In a single-threaded environment, you do not want to pay the costs. An implementation could therefore implement the synchronization functions as empty stubs, and declare the functions as weak symbols.
Later, if a multi-threading library is linked (e.g., pthread), it becomes obvious that single-thread support is not intended. When linking the multi-threading library, the linker can then replace the stubs by the real synchronization functions (defined as strong symbols and implemented by the threading-library). On the other hand, if no multi-threading library is linked, the executable will use the stubs for the synchronization function.
glibc (providing fputc) and pthreads seem to use exactly this trick. For details, refer to this question about the usage of weak symbols in glibc. The example above is taken from this answer.
nm allows you to look at it in detail, which seems consistent with the cited answer above:
$ nm /usr/lib/libc.a 2>/dev/null | grep pthread_mutex_lock
w __pthread_mutex_lock
... (repeats)
"w" stands for "weak", so the statically linked libc library contains __pthread_mutex_lock as a weak symbol. The statically linked pthread library contains it as a strong symbol:
$ nm /usr/lib/libpthread.a 2>/dev/null | grep pthread_mutex_lock
U pthread_mutex_lock
pthread_mutex_lock.o:
00000000000006a0 T __pthread_mutex_lock
00000000000006a0 T pthread_mutex_lock
0000000000000000 t __pthread_mutex_lock_full
Back to the example program
By looking at the shared library dependencies of the dynamically linked executable, I get almost the same output of ldd on my machine:
$ ldd one
linux-vdso.so.1 (0x00007fff79d6d000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007fcaaeeb3000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007fcaaeb9b000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007fcaae983000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fcaae763000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fcaae3bb000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcaaf23b000)
Printing out the library calls with ltrace, leads to the following output:
$ ltrace -C ./one
std::ios_base::Init::Init()(0x563ab8df71b1, 0x7ffdc483cae8, 0x7ffdc483caf8, 160) = 0
__cxa_atexit(0x7fab3023bc20, 0x563ab8df71b1, 0x563ab8df7090, 6) = 0
operator new(unsigned long)(16, 0x7ffdc483cae8, 0x7ffdc483caf8, 192) = 0x563ab918bc20
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2f6a1fb0, 0, 0x800000) = 0x563ab918bd70
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2eea0fb0, 0, 0x800000) = 0x563ab918bec0
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
) = 0
operator new(unsigned long)(16, 0x7fab2e69ffb0, 0, 0x800000) = 0x563ab918c010
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
test start
) = 0
std::thread::join()(0x7ffdc483c9a0, 0x7fab2de9efb0, 0, 0x800000test start
test release
test release
test release
test release
test end
test end
test end
test end
) = 0
std::thread::join()(0x7ffdc483c9a8, 0x7fab2eea19c0, 0x7fab2f6a2700, 0) = 0
std::thread::join()(0x7ffdc483c9b0, 0x7fab2e6a09c0, 0x7fab2eea1700, 0) = 0
std::thread::join()(0x7ffdc483c9b8, 0x7fab2de9f9c0, 0x7fab2e6a0700, 0) = 0
+++ exited (status 0) +++
As an example, std::thread::join is called, which will most likely use pthread_join internally. That symbol can be found in the (dynamically linked) libraries listed in the ldd ouput, namely in libstdc++.so.6 and libpthread.so.0:
$ nm /usr/lib/libstdc++.so.6 | grep pthread_join
w pthread_join
$ nm /usr/lib/libpthread.so.0 | grep pthread_join
0000000000008280 T pthread_join
In the dynamically linked executable, the linker will replace weak symbols by strong symbols. In this example, we have to enforce the same semantic for the statically linked libraries. That is why -Wl,--whole-archive -lpthread -Wl,--no-whole-archive is needed.
Finding it out is a bit trial-and-error. At least, I found no clear documentation on that subject. I assume it is because static linking on Linux has become rather an edge case, whereas dynamic linking is often the canonical approach on how to use the libraries (for a comparison, see Static linking vs dynamic linking). The most extreme example that I have seen and personally struggled with a while to get it working is to link TBB statically.
Appendix: Workaround for Autotools
If you are using autotools as a build system, you need a workaround, as automake does not let you set options in the in LDADD. Unfortunately, you cannot write:
(Makefile.am)
mytarget_LDADD = -Wl,--whole-archive -lpthread -Wl,--no-whole-archive
As a workaround, you can avoid the check by defining the flags in configure.ac, and using them like this:
(configure.ac)
WL_WHOLE_ARCHIVE_HACK="-Wl,--whole-archive"
WL_NO_WHOLE_ARCHIVE_HACK="-Wl,--no-whole-archive"
AC_SUBST(WL_WHOLE_ARCHIVE_HACK)
AC_SUBST(WL_NO_WHOLE_ARCHIVE_HACK)
(Makefile.am)
mytarget_LDADD = #WL_WHOLE_ARCHIVE_HACK# -lpthread #WL_NO_WHOLE_ARCHIVE_HACK#
I had similar issue when linking a pre-built C++ .a archive that uses pthread. In my case I needed in addition to -Wl,--whole-archive -lpthread -Wl,--no-whole-archive also do -Wl,-u,... for each weak symbol.
My symptom was crashes at runtime and when using gdb to disassemble I could see that the crash was just after a callq 0x0 which seemed suspicious. Did some seaching and found that others had seen this with static pthread linking.
I figured out which symbols to force resolve by using nm and look for w symbols. After linking I could then see that the callq 0x0 instructions had been updated with various symbol addresses to pthread_mutex_lock etc.

when g++ static link pthread, cause Segmentation fault, why?

#include <iostream>
#include <map>
#include <thread>
#define SIZE 1024
#define AMOUNT 100000
#define THREADS 4
class A
{
private:
char a[SIZE];
};
void test()
{
std::cout << "test start\n";
std::map<int, A*> container;
for(int i=0; i<AMOUNT; i++)
{
A* a = new A();
std::pair<int, A*>p = std::make_pair(i, a);
container.insert(p);
}
std::cout << "test release\n";
for(int i=0; i<AMOUNT; i++)
{
auto iter = container.find(i);
delete iter->second;
container.erase(iter);
}
std::cout << "test end\n";
}
int main()
{
std::thread ts[THREADS];
for(int i=0; i<THREADS; i++)
{
ts[i] = std::thread(test);
}
for(std::thread& x: ts)
{
x.join();
}
return 0;
}
Above is a simple c++ code.
compile with: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3
ldd one, gots:
linux-vdso.so.1 => (0x00007ffebafce000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fb47352a000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fb473313000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb4730f4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb472d2a000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb472a22000)
/lib64/ld-linux-x86-64.so.2 (0x00005654c5112000)
run ./one, every thing is ok.
Then I try a static link: g++ -pthread -o one one.cpp -Wall -std=c++11 -O3 -static
ldd one, gots:
not a dynamic executable
But when I run it, some thing goes wrong...
test start
Segmentation fault (core dumped)
re-compile with -g, and the gdb shows:
wang[00:35][~/test]$ gdb one
GNU gdb (Ubuntu 7.10-1ubuntu2) 7.10
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from one...done.
(gdb) run
Starting program: /home/wang/test/one
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7ffa700 (LWP 3623)]
test start
[New Thread 0x7ffff77f8700 (LWP 3624)]
test start
[New Thread 0x7ffff6ff7700 (LWP 3625)]
test start
[New Thread 0x7ffff67f6700 (LWP 3626)]
test start
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb)
Why this ?
UPDATE
==============================
using boost::thread library (boost version: 1.60),
replace std::thread with boost::thread , and make a static link,
g++ -pthread -o one1 one.cpp -Wall -std=c++11 -O3 -I /opt/boost/include/ -L /opt/boost/lib/ -lboost_system -lboost_thread -static
no problem occurred!
confused...
First, the solution. This here will work:
Update: Since Ubuntu 18.04, you need to link also against librt (add -lrt):
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -lrt -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
(continue with original answer)
g++ -o one one.cpp -Wall -std=c++11 -O3 -static -pthread \
-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
When you use -pthread, the compiler will already link against pthread (and depending on the platform, it does define extra macros like -D_REENTRANT, see this question for more details).
So if -pthread implies -lpthread, why do you need you specify -lpthread when you are linking statically? And what does Wl,--whole-archive do?
Understanding weak symbols
On Unix, the ELF file format is used, which has the concept of weak and strong symbols. To quote from the Wikipedia page:
By default, without any annotation, a symbol in an object file is strong. During linking, a strong symbol can override a weak symbol of the same name. In contrast, two strong symbols that share a name yield a link error during link-time.
There is a subtle difference when it comes to dynamic and static libraries. In static libraries, the linker will stop at the first symbol, even if it is a weak one, and stops looking for strong ones. To force it to look at all symbols (like it would have done for a dynamically linked library), ld supports the --whole-archive option.
To quote from man ld:
--whole-archive:
For each archive mentioned on the command line after the --whole-archive option, include every object file in the archive in the
link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a
shared library, forcing every object to be included in the resulting shared library. This option may be used more than once.
It goes on by explaining that from gcc, you have to pass the option as -Wl,--whole-archive:
Two notes when using this option from gcc: First, gcc doesn't know about this option, so you have to use -Wl,-whole-archive.
Second, don't forget to use -Wl,-no-whole-archive after your list of archives, because gcc will add its own list of archives to
your link and you may not want this flag to affect those as well.
And it explains how to turn it off, again:
--no-whole-archive:
Turn off the effect of the --whole-archive option for subsequent archive files.
Weak symbols in pthread and libstdc++
One of the use cases of weak symbols is to be able to swap out implementations with optimized ones. Another is to use stubs, which can later to replaced if necessary.
For example, fputc (conceptionally used by printf) is required by POSIX to be thread-safe and needs to be synchronized, which is costly. In a single-threaded environment, you do not want to pay the costs. An implementation could therefore implement the synchronization functions as empty stubs, and declare the functions as weak symbols.
Later, if a multi-threading library is linked (e.g., pthread), it becomes obvious that single-thread support is not intended. When linking the multi-threading library, the linker can then replace the stubs by the real synchronization functions (defined as strong symbols and implemented by the threading-library). On the other hand, if no multi-threading library is linked, the executable will use the stubs for the synchronization function.
glibc (providing fputc) and pthreads seem to use exactly this trick. For details, refer to this question about the usage of weak symbols in glibc. The example above is taken from this answer.
nm allows you to look at it in detail, which seems consistent with the cited answer above:
$ nm /usr/lib/libc.a 2>/dev/null | grep pthread_mutex_lock
w __pthread_mutex_lock
... (repeats)
"w" stands for "weak", so the statically linked libc library contains __pthread_mutex_lock as a weak symbol. The statically linked pthread library contains it as a strong symbol:
$ nm /usr/lib/libpthread.a 2>/dev/null | grep pthread_mutex_lock
U pthread_mutex_lock
pthread_mutex_lock.o:
00000000000006a0 T __pthread_mutex_lock
00000000000006a0 T pthread_mutex_lock
0000000000000000 t __pthread_mutex_lock_full
Back to the example program
By looking at the shared library dependencies of the dynamically linked executable, I get almost the same output of ldd on my machine:
$ ldd one
linux-vdso.so.1 (0x00007fff79d6d000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007fcaaeeb3000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007fcaaeb9b000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007fcaae983000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fcaae763000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fcaae3bb000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcaaf23b000)
Printing out the library calls with ltrace, leads to the following output:
$ ltrace -C ./one
std::ios_base::Init::Init()(0x563ab8df71b1, 0x7ffdc483cae8, 0x7ffdc483caf8, 160) = 0
__cxa_atexit(0x7fab3023bc20, 0x563ab8df71b1, 0x563ab8df7090, 6) = 0
operator new(unsigned long)(16, 0x7ffdc483cae8, 0x7ffdc483caf8, 192) = 0x563ab918bc20
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2f6a1fb0, 0, 0x800000) = 0x563ab918bd70
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80) = 0
operator new(unsigned long)(16, 0x7fab2eea0fb0, 0, 0x800000) = 0x563ab918bec0
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
) = 0
operator new(unsigned long)(16, 0x7fab2e69ffb0, 0, 0x800000) = 0x563ab918c010
std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)())(0x7ffdc483c990, 0x7ffdc483c998, 0x7fab2fa52320, 0x7fab2fa43a80test start
test start
) = 0
std::thread::join()(0x7ffdc483c9a0, 0x7fab2de9efb0, 0, 0x800000test start
test release
test release
test release
test release
test end
test end
test end
test end
) = 0
std::thread::join()(0x7ffdc483c9a8, 0x7fab2eea19c0, 0x7fab2f6a2700, 0) = 0
std::thread::join()(0x7ffdc483c9b0, 0x7fab2e6a09c0, 0x7fab2eea1700, 0) = 0
std::thread::join()(0x7ffdc483c9b8, 0x7fab2de9f9c0, 0x7fab2e6a0700, 0) = 0
+++ exited (status 0) +++
As an example, std::thread::join is called, which will most likely use pthread_join internally. That symbol can be found in the (dynamically linked) libraries listed in the ldd ouput, namely in libstdc++.so.6 and libpthread.so.0:
$ nm /usr/lib/libstdc++.so.6 | grep pthread_join
w pthread_join
$ nm /usr/lib/libpthread.so.0 | grep pthread_join
0000000000008280 T pthread_join
In the dynamically linked executable, the linker will replace weak symbols by strong symbols. In this example, we have to enforce the same semantic for the statically linked libraries. That is why -Wl,--whole-archive -lpthread -Wl,--no-whole-archive is needed.
Finding it out is a bit trial-and-error. At least, I found no clear documentation on that subject. I assume it is because static linking on Linux has become rather an edge case, whereas dynamic linking is often the canonical approach on how to use the libraries (for a comparison, see Static linking vs dynamic linking). The most extreme example that I have seen and personally struggled with a while to get it working is to link TBB statically.
Appendix: Workaround for Autotools
If you are using autotools as a build system, you need a workaround, as automake does not let you set options in the in LDADD. Unfortunately, you cannot write:
(Makefile.am)
mytarget_LDADD = -Wl,--whole-archive -lpthread -Wl,--no-whole-archive
As a workaround, you can avoid the check by defining the flags in configure.ac, and using them like this:
(configure.ac)
WL_WHOLE_ARCHIVE_HACK="-Wl,--whole-archive"
WL_NO_WHOLE_ARCHIVE_HACK="-Wl,--no-whole-archive"
AC_SUBST(WL_WHOLE_ARCHIVE_HACK)
AC_SUBST(WL_NO_WHOLE_ARCHIVE_HACK)
(Makefile.am)
mytarget_LDADD = #WL_WHOLE_ARCHIVE_HACK# -lpthread #WL_NO_WHOLE_ARCHIVE_HACK#
I had similar issue when linking a pre-built C++ .a archive that uses pthread. In my case I needed in addition to -Wl,--whole-archive -lpthread -Wl,--no-whole-archive also do -Wl,-u,... for each weak symbol.
My symptom was crashes at runtime and when using gdb to disassemble I could see that the crash was just after a callq 0x0 which seemed suspicious. Did some seaching and found that others had seen this with static pthread linking.
I figured out which symbols to force resolve by using nm and look for w symbols. After linking I could then see that the callq 0x0 instructions had been updated with various symbol addresses to pthread_mutex_lock etc.

Using libc++ causes GDB to segfault on OS X

I'm trying to use C++11 (with Clang and libc++ on OS X) for a program, but whenever I debug with gdb and try to inspect standard containers, gdb segfaults. Here's a minimal example:
file.cpp:
#include <iostream>
#include <string>
int main(int argc, char* argv[])
{
std::string str = "Hello world";
std::cout << str << std::endl; // Breakpoint here
}
If I compile for C++11 using the following:
$ c++ --version
Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin12.4.0
Thread model: posix
$
$ c++ -ggdb -std=c++11 -stdlib=libc++ -Wall -pedantic -O0 -c file.cpp
$ c++ -ggdb -std=c++11 -stdlib=libc++ -Wall -pedantic -O0 file.o -o program
And then debug as follows, it crashes when I try to p str.size():
$ gdb program
GNU gdb 6.3.50-20050815 (Apple version gdb-1824) (Wed Feb 6 22:51:23 UTC 2013)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared libraries ... done
(gdb) br file.cpp:8
Breakpoint 1 at 0x100000d80: file file.cpp, line 8.
(gdb) run
Starting program: /Users/mjbshaw/School/cs6640/2/program
Reading symbols for shared libraries ++............................. done
Breakpoint 1, main (argc=1, argv=0x7fff5fbffab0) at file.cpp:8
8 std::cout << str << std::endl; // Breakpoint here
(gdb) p str.size()
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000000
std::__1::operator<< <char, std::__1::char_traits<char>, std::__1::allocator<char> > (__os=#0x7fff5fc3d628, __str=#0x1) at string:1243
1243
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on"
Evaluation of the expression containing the function (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::__is_long() const) will be abandoned.
If I don't run this in gdb, I get no crash and it works fine (but I need gdb to debug my program). Also, if I remove -std=c++11 -stdlib=libc++ from the compiling options, then it works fine (even in gdb), but I need C++11 for my program.
Are there some known issues with gdb and C++11 (specifically libc++)? I know libc++ and libstdc++ can cause issues if used together, but I'm not trying to use them together (at least not consciously; all I want to use is libc++). Am I specifying some compilation options wrong? Is there a way to properly compile for C++11 on OS X and still be able to debug properly?
GDB 6.3 is almost nine years old. That's just about eternity in Internet years. The product has improved greatly since then. Updating to the last stable release is a must for every developer.