针对pthread的静态链接在Linux上是一个困难的话题。它曾经用于将-lpthread
包装为-Wl,--whole-archive -lpthread -Wl,--no-whole-archive
(详细信息可以在answer中找到)。
结果是(用于pthread的符号为strong, not weak。自从Ubuntu 18.04左右(在gcc 5.4.0和gcc 7.4.0之间)以来,这种行为似乎已经改变,并且pthread符号现在总是以弱符号结尾,而与--whole-archive
选项无关。
因此,-whole-archive
配方停止工作。我的问题的目的是了解工具链中最近发生了哪些变化(编译器,链接器,标准库),以及可以采取哪些措施来恢复旧的行为。
示例:
#include <mutex>
int main(int argc, char **argv) {
std::mutex mutex;
mutex.lock();
mutex.unlock();
return 0;
}
在以下所有示例中,使用了相同的编译命令:
g++ -std=c++11 -Wall -static simple.cpp -Wl,--whole-archive -lpthread -Wl,--no-whole-archive
[以前,使用-static
进行编译时,pthread符号(例如pthread_mutex_lock
)很强(由T
标记为nm
),但是现在它们很弱(nm
:]]]
Ubuntu 14.04:W
docker run --rm -it ubuntu:14.04 bash
Ubuntu 16.04:
$ apt-get update $ apt-get install g++ $ g++ --version g++ (Ubuntu 4.8.4-2ubuntu1~14.04.4) 4.8.4 $ nm a.out | grep pthread_mutex_lock 0000000000408160 T __pthread_mutex_lock 00000000004003e0 t __pthread_mutex_lock_full 0000000000408160 T pthread_mutex_lock
docker run --rm -it ubuntu:16.04 bash
Ubuntu 18.04:
$ g++ --version g++ (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609 $ nm a.out | grep pthread_mutex_lock 00000000004077b0 T __pthread_mutex_lock 0000000000407170 t __pthread_mutex_lock_full 00000000004077b0 T pthread_mutex_lock
docker run --rm -it ubuntu:18.04 bash
总结:
$ g++ --version
g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
$ nm ./a.out | grep pthread_mutex_lock
0000000000407010 T __pthread_mutex_lock
00000000004069d0 t __pthread_mutex_lock_full
0000000000407010 W pthread_mutex_lock
(强符号)T pthread_mutex_lock
(弱符号)在更复杂的示例中,这可能会导致分段错误。例如,在此代码中(可以找到未修改的文件W pthread_mutex_lock
):
here尝试生成静态二进制文件失败,例如:
#include <pthread.h> #include <thread> #include <cstring> #include <iostream> #include <mutex> #include <thread> #include <vector> std::mutex mutex; void myfunc(int i) { mutex.lock(); std::cout << i << " " << std::this_thread::get_id() << std::endl << std::flush; mutex.unlock(); } int main(int argc, char **argv) { std::cout << "main " << std::this_thread::get_id() << std::endl; std::vector<std::thread> threads; unsigned int nthreads; if (argc > 1) { nthreads = std::strtoll(argv[1], NULL, 0); } else { nthreads = 1; } for (unsigned int i = 0; i < nthreads; ++i) { threads.push_back(std::thread(myfunc, i)); } for (auto& thread : threads) { thread.join(); } }
我试图删除
$ g++ thread_get_id.cpp -Wall -std=c++11 -O3 -static -pthread -Wl,--whole-archive -lpthread -Wl,--no-whole-archive $ ./a.out Segmentation fault (core dumped)
,切换到-O3
,切换到Gold链接器,等等。但是它总是崩溃。据我了解,静态二进制文件崩溃的原因是基本功能(例如clang++
)不会以强符号结尾。因此,它们在最终的二进制文件中丢失,从而导致运行时错误。
除了Ubuntu 18.04,我还可以在带有gcc 10.0.0的Arch Linux上重现相同的行为。但是,在Ubuntu 14.04和16.04上,可以创建和执行静态二进制文件,而不会出现任何错误。
问题:
pthread_mutex_lock
下降了。也许是原因吗?)针对pthread的静态链接在Linux上是一个困难的话题。它曾经用于将-lpthread包装为-Wl,-整个存档-lpthread -Wl,-没有整个存档(详细信息可在此答案中找到)。 ...
新解决方法:pthread cleanup for C11