GCC:-静态链接到pthread的--whole-archive配方在最新的gcc版本中停止工作

问题描述 投票:2回答:1

针对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

总结:

  • Ubuntu 14.04和16.04:$ 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 (强符号)
  • Ubuntu 18.04: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上,可以创建和执行静态二进制文件,而不会出现任何错误。

问题:

  • [构建工具链中的哪些变化(在gcc 5.4.0和gcc 7.4.0之间? (大胆的猜测:我看到那个时期的pthread_mutex_lock下降了。也许是原因吗?)
  • 是回归,还是旧的解决方法不再正确。
  • 如果没有回归,应该怎么做才能允许静态链接到pthread?

针对pthread的静态链接在Linux上是一个困难的话题。它曾经用于将-lpthread包装为-Wl,-整个存档-lpthread -Wl,-没有整个存档(详细信息可在此答案中找到)。 ...

c++ gcc pthreads static-linking
1个回答
1
投票

新解决方法:pthread cleanup for C11

© www.soinside.com 2019 - 2024. All rights reserved.