lib OSMesa 屏幕外上下文创建在C++中失败,但仅在静态链接时失败



我做了一个C++工具,用于3D模型的屏幕外渲染。渲染是使用 OSMesa 库完成的。

该软件完美运行了一年多,我停止对它进行更新,就像 6 个月前一样。与此同时,我的开发环境被多次更新。

现在我再次编译它,发现了一个意想不到的错误。

该软件的普通版本仍在按预期工作,但静态链接的版本存在段错误。

我假设错误是我在 OSmesa 配置/编译/链接过程中而不是在库代码中,但任何关于更好地调试分段错误的建议都值得赞赏。

在尝试了编译过程的许多变体但没有成功之后,我现在很卡住了。 任何人都可以在下面描述的一些步骤中看到我正在做的事情?


我用与我的系统(12.0.6)中运行的共享库版本相同重新编译了OSmesa库的静态版本,禁用了所有不需要的功能(使用基于Ubuntu的系统,存储库中没有可用的OSmesa lib的静态版本):

。/配置\ --禁用-xvmc \ --禁用-glx \ --禁用-dri \ --with-dri-drivers=" \ --带镓驱动程序=" \ --禁用-共享-glapi \ --禁用-EGL \ --with-egl-platforms=" \ --启用-奥斯梅萨 \ --enable-gallium-llvm=no \ --禁用-gles1 \ --禁用-gles2 \ --启用静态 \ --禁用共享

这是我的屏幕外渲染工具的编译命令:

g++ -
std=c++11 -wall -O3 -g -static -static-libgcc -static-libstdc++ ./src/measure_model.cpp model.o thumbnail.o -o measure_model_debug -pthread -lOSMesa -ldl -lm -lpng -lz -lcrypto

这是我通过使用OSMesa静态编译而得到的警告,甚至在一年前,它就存在于工作静态二进制文件中:

/home/XXX/
XXX/backend/lambda/mesa/mesa-12.0.6/src/mesa/main/dlopen.h:52: 警告:在静态链接的应用程序中使用"dlopen"需要在运行时使用用于链接的glibc版本中的共享库

这是我从运行该工具中获得的:

分段错误(核心转储)

但是如果我简单地跳过 OSmesa 上下文创建步骤(显然是所有 3D 渲染),就不会产生分段错误

这是回溯:

#0 0x0000000000000000在??() #1 0x00000000004af20a 在 mtx_init (类型=4, mtx=0xe10f70) 在 ../../include/c11/threads_posix.h:215 #2 _mesa_NewHashTable () at main/hash.c:135 #3 0x000000000052f295 in _mesa_alloc_shared_state (ctx=ctx@entry=0xdcc9b0) at main/shared.c:67 #4 0x000000000046e717 in _mesa_initialize_context (ctx=ctx@entry=0xdcc9b0, api=api@entry=API_OPENGL_COMPAT, visual=, share_list=share_list@entry=0x0, driverFunctions=driverFunctions@entry=0x7fffffffcd40) at main/context.c:1192 #5 0x000000000046c870 in OSMesaCreateContextAttribs (attribList=attribList@entry=0x7fffffffd290, sharelist=) at osmesa.c:834 #6 0x000000000046ccdc in OSMesaCreateContextExt (format=, depthBits=, stencilBits=, accumBits=, sharelist=) at osmesa.c:660 #7 0x0000000000468742 in generate_thumbnail(模型*, Json::值) () #8 在 main (argc=, argv=) 中0x0000000000401c7d 在 ./src/measure_model.cpp:107

静态链接的二进制文件是一项严格的要求。

分割错误发生在我用来编译工具的同一台机器上(OSmesa static lib 也在同一台机器上编译),但在同一工具的非静态链接版本中没有分割错误。

这是我从运行该工具中获得的:Segmentation fault (core dumped)

但是,如果我简单地跳过OSmesa上下文创建步骤(显然是所有3D渲染),则不会产生分段错误

因此,OSmesa创建存在一些问题。通过您的回溯,我们可以看到 top 函数是从零的 EIP 执行的(跳转到 NULL/调用 NULL),因此在mtx_init中调用了一些函数,这是 OS Mesa上下文创建的一部分。

#0  0x0000000000000000 in ?? ()
#1  0x00000000004af20a in mtx_init (type=4, mtx=0xe10f70) at ../../include/c11/threads_posix.h:215
#2  _mesa_NewHashTable () at main/hash.c:135
#3  0x000000000052f295 in _mesa_alloc_shared_state (ctx=ctx@entry=0xdcc9b0) at main/shared.c:67
#4  0x000000000046e717 in _mesa_initialize_context (ctx=ctx@entry=0xdcc9b0, api=api@entry=API_OPENGL_COMPAT, visual=, share_list=share_list@entry=0x0, driverFunctions=driverFunctions@entry=0x7fffffffcd40) at main/context.c:1192
#5  0x000000000046c870 in OSMesaCreateContextAttribs (attribList=attribList@entry=0x7fffffffd290, sharelist=) at osmesa.c:834
#6  0x000000000046ccdc in OSMesaCreateContextExt (format=, depthBits=, stencilBits=, accumBits=, sharelist=) at osmesa.c:660
#7  0x0000000000468742 in generate_thumbnail(Model*, Json::Value) ()
#8  0x0000000000401c7d in main (argc=, argv=) at ./src/measure_model.cpp:107

功能是什么?根据 include/c11/threads_posix.h:mtx_init()在 github 上的在线资源,只有对 libpthread (-lpthreadpthread_mutex_initpthread_mutexattr_init和其他几个与互斥锁相关的函数的调用。

为什么产生对 NULL 而不是实际函数的调用?可能是由于使用了 glibc 和/或 libpthread 的静态链接。目前仍未确定确切的问题(我能够找到静态链接的libpthread.a到一些共享库的报告,这是不正确的,永远不会起作用)。

在您的情况下,glibc/nptl/pthread_mutex_init.c(第 150 行)strong_alias (__pthread_mutex_init, pthread_mutex_init)中只有pthread_mutex_init的别名(强别名),并且 glibc 本身中可能存在符号的一些弱别名,可能未初始化。有些在你的链接选项或/和ld脑海中是错误的,他没有找到/链接带有真实符号的nptl/pthread_mutex_init.o(它是libpthread.a archive的一部分)到最终可执行文件中(ld 经常跳过 .a archive 中未使用/不需要的对象并且不将它们链接到最终可执行文件),保持重定位指向 NULL。一些glibc专家可能知道,受雇的俄罗斯人是SO的专家之一。

我建议仅静态链接到您的内部库,或者也可能链接到像 mesa 这样的普通非系统库(您可以使用-Wl,-Bstatic -lyour_lib -Wl,-Bdynamic选项将链接临时更改为静态之间列出的库;或使用 Radek 在同一 q 中找到的-l:libYour_lib.a-l:作弊选项)。但是不要静态链接到 glibc 的大多数基本库,如 libc、libpthread、librt(使用 nss 时,glibc 的静态链接存在一些问题:目标系统必须具有完全相同版本的动态 glibc 才能使 nss 工作)。

如果你想为旧机器打包你的应用程序,并且你需要glibc的一些功能,你也可以尝试将你自己的共享glibc库版本与你的应用程序打包在一起;把它们放在某个子目录中,添加链接器rpath选项来更改库搜索路径,还将INTERP部分从默认的ABI ld-linux.so.2加载器更改为你自己的glibc版本ld-linux.so.2副本, ...而且你仍然会遇到太旧的内核的问题,因为较新的glibcs需要一些相当新的内核的现代功能(系统调用,结构)。

或者你可以将你的应用程序打包到某种容器中,比如Docker,或者其他一些隔离解决方案(或chroot?),以始终拥有你的库版本......

更新:刚刚发现类似的 bt 报告,使用 NULL 而不是来自 nptl 的互斥实现:https://bugzilla.redhat.com/show_bug.cgi?id=163083"使用 pthreads 的静态链接C++程序将出现段错误"(2005-2007)pthread_mutex_init(&lock, NULL);g++ -g -static foo.cpp -o foo -lpthreadwhere #0 0x00000000 in ?? () #1 0x08048232 in main () at foo.cpp:7

这显然是由于某些 pthreads 函数未包含在输出可执行文件中。 此错误可能会重复#115157,如果是这样,我深表歉意,但希望包含的测试用例会很有用。

附加信息:

#115157 中强制链接所有 libpthread.a 的建议是一种有效的解决方法。

https://bugzilla.redhat.com/show_bug.cgi?id=115157 "与/usr/lib/nptl/libpthread.a 静态链接的可执行文件失败" - 2004-2009 已关闭

Jakub Jelinek 2004-10-29 05:26:10 EDT

首先,如果可以的话,避免-static,它只会产生问题, 便携性和其他方面也是如此。

如果您确实需要使用-lpthread创建静态链接的二进制文件 链接,然后只需使用-Wl,--whole-archive -lpthread -Wl,--no-whole-archive而不是-pthread. 其他任何事情都有很多问题。

相关内容

  • 没有找到相关文章

最新更新