【问题标题】:pthread_atfork fails to compile when declaring -nostartfiles声明 -nostartfiles 时 pthread_atfork 无法编译
【发布时间】:2015-03-16 05:11:42
【问题描述】:

我有一个旧应用程序,它使用 pthread 库中的 pthread_atfork 函数来注册子挂钩。我正在将应用程序移动到使用 glibc 2.14.90 的更新的构建环境。 pthread_atfork 似乎早在 2002 年就已从 pthread 库中删除,我们创建的共享库之一将不再编译。

这里是有问题的代码:

void
_init(void)
{
    static int first = 1;
    if ( first ) {
        pthread_atfork(NULL,NULL,_init);
        first = 0;
    }
    {
        pthread_t tid;
        pthread_create(&tid,0,startUp,0);
    }
    return;
}

pthread_atfork 调用将 _init 注册为子挂钩,每次有 fork 时都会在子进程中运行。 Init 只是创建一个新线程来执行 startUp,它是一个初始化函数,用于设置文件、互斥体、读取初始化参数等内容......

由于 pthread_atfork 隐藏在 glibc 2.14 中,是否有另一种方法来注册相同类型的钩子,以便 init 在 fork 处运行?我宁愿使用标准库而不做任何修改,以保持构建环境的可移植性。

glibc 2.14 源代码在这里,有兴趣的朋友可以看看(pthread_atfork 文件在 nptl 目录下):

https://sourceware.org/git/?p=glibc.git;a=tree;h=d1e550124ee36b8b62af8984e4b829622a60f725;hb=356f8bc660a154a07b03da7c536831da5c8f74fe

我收到编译错误:

gcc -g -nostartfiles -o mto.so -shared -I mto.c -lnsl -lresolv -lrt -lm -lpthread -ldl

/usr/bin/ld: /usr/lib/libpthread_nonshared.a(pthread_atfork.oS): 重定位 R_386_GOTOFF 针对未定义的隐藏符号 `__dso_handle' 在制作共享对象时不能使用

$ gcc -v

使用内置规范。 COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/libexec/gcc/i686-redhat-linux/4.6.3/lto-wrapper 目标:i686-redhat-linux 配置为:../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable -shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker- build-id --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-java-awt=gtk --disable-dssi --with -java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/ usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch=i686 --build=i686-redhat- linux 线程模型:posix gcc 版本 4.6.3 20120306 (Red Hat 4.6.3-2) (GCC)

$ ldd --version

ldd (GNU libc) 2.14.90 版权所有 (C) 2011 Free Software Foundation, Inc. 这是免费软件;查看复制条件的来源。没有 保修单;甚至不考虑适销性或特定用途的适用性。 由 Roland McGrath 和 Ulrich Drepper 撰写。

$ nm /usr/lib/libpthread.a|grep -C 1 atfork
00008150 W __pread64
000060b0 T __pthread_atfork
00002ab0 T __pthread_attr_destroy
--
00007ba0 W __recvmsg
         U __register_atfork
00008c10 T __res_state
--
00008150 W pread64
000060b0 T pthread_atfork
00002ab0 T pthread_attr_destroy

.

$ nm /usr/lib/libpthread_nonshared.a

pthread_atfork.oS:
         U _GLOBAL_OFFSET_TABLE_
         w __dso_handle
00000000 T __i686.get_pc_thunk.bx
00000000 T __pthread_atfork
         U __register_atfork
00000000 T pthread_atfork

感谢您的宝贵时间。

【问题讨论】:

  • 我不确定是什么让您认为 pthread_atfork 已被删除;它不是。如果您遇到实际问题,请显示您收到的错误消息。请记住,_init 是一个特别糟糕的函数名称。它位于保留的命名空间中,最终可能会被链接过程特殊处理。
  • 阅读 POSIX 2008 规范中pthread_atfork() 的基本原理,您会看到很多过去时:pthread_atfork() 函数旨在提供……预期用途是……这是理论上不错,但实际上不实用……对于需要通过互斥锁和锁保护非原子操作的功能没有合适的解决方案……POSIX.1 标准……要求fork() 之后的子进程在多线程进程只调用异步信号安全接口。
  • @JonathanLeffler:确实它在 POSIX 中被非正式地弃用了,但它并没有从 glibc 中删除,它仍然试图支持 POSIX 的古老版本,甚至当前的 POSIX 仍然提供pthread_atfork
  • @ktbiz:这不是让代码在加载库时自动运行的正确方法。你应该使用__attribute__((__constructor__))
  • @ktbiz:摆脱-nostartfiles,我怀疑你的问题会消失。

标签: c pthreads shared-libraries fork glibc


【解决方案1】:

您的问题是外部包装函数 pthread_atfork 似乎已移至 libpthread_nonshared.a 以便它可以识别调用它的库,大概是这样当库被卸载时,安装的处理程序可以被删除,它通过引用在开始文件中定义的__dso_handle 符号来实现这一点,您有意省略了该符号。 您不能这样做。 省略启动文件仅对某些低级用途有效;它与链接标准库的任何部分都不兼容。

显然您使用-nostartfiles 的原因是能够编写您自己的_init 函数,该函数将在加载库时运行,因为没有-nostartfiles 它会由于与crti.o 中的同名函数。不幸的是,这是错误的解决方法。

重新定义 _init 以在库加载时运行代码是一种不受支持的 hack,很久以前就已弃用。在库加载时运行代码的正确方法是将__attribute__((__constructor__)) 应用于您要运行的函数。给函数起一个不会与任何内容冲突的名称,或者将其命名为 static,这样您就不必担心它的名称冲突。

【讨论】:

  • 奇怪的是,__attribute__((__constructor__)) _init(void) 声明已经在文件中,但它被隐藏在顶部的 #ifdef (linux) 声明中。为什么没有更改函数名称?也许是懒惰或试图使此代码与非常旧的 gcc 版本兼容。此代码还必须在 solaris 上的 sun 编译器下编译,该编译器有自己的初始化 def #define _init _localInit 隐藏在 #ifdef 语句中。我更改了 _init 函数的名称并去掉了 -nostartfiles(和 _fini)。感谢您的帮助。
猜你喜欢
  • 2014-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-01
  • 2020-12-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多