登录
首页 >  Golang >  Go问答

重复调用(dlopen)和取消加载(dlclose)同一共享对象导致段错误

来源:stackoverflow

时间:2024-02-11 14:12:24 335浏览 收藏

最近发现不少小伙伴都对Golang很感兴趣,所以今天继续给大家介绍Golang相关的知识,本文《重复调用(dlopen)和取消加载(dlclose)同一共享对象导致段错误》主要内容涉及到等等知识点,希望能帮到你!当然如果阅读本文时存在不同想法,可以在评论中表达,但是请勿使用过激的措辞~

问题内容

在我的代码中,我有一个 for 循环,首先调用 dlopen 来加载共享对象,然后调用已加载库的函数,然后调用 dlclose 来卸载它。循环的第一次迭代按预期工作,但在第二次迭代期间(当 i=1 时)dlopen 调用导致分段错误(核心转储)。

void *handle;
    char* (*goimg)();
    char *error;
    int i;
    for (i=0; i<5; i++) {
        handle = dlopen("mylib.so", rtld_lazy);
        if (!handle) {
            fputs (dlerror(), stderr);
            exit(1);
        }

       goimg = dlsym(handle, "writetofileinwrapper");
       if ((error = dlerror()) != null)  {
           fputs(error, stderr);
           exit(1); }
       goimg();

        if (!handle) {
            fputs (dlerror(), stderr);
            exit(1);
        }
       dlclose(handle);
   }

生成mylib.so的脚本:

echo "Building golang code to create an archive file."
go build -buildmode=c-archive -o bin/goHelper.a goHelper.go

echo "Building wrapperCodeInC to be consumed as a shared library."
gcc -c -fPIC -o bin/shared/wrapperCodeInC.o -I./bin -I./wrapper wrapper/wrapperCodeInC.c

gcc -s -shared -lpthread -Wl,-Bsymbolic -o bin/mylib.so -Wl,--whole-archive bin/goHelper.a -Wl,--no-whole-archive bin/shared/wrapperCodeInC.o

这里,gohelper.go 有一些用 go 语言编写的函数,而wrappercodeinc.c 有包装函数来调用这些 go 函数。

在循环的第一次运行中,dlopen()、goimg() 和 dlclose() 按预期工作,但在第二次运行期间 (i=1),dlopen 正在转储核心。知道是什么原因造成的吗?

注意:如果我从构建文件中删除 -wl,-bsymbolic,则会收到类似于此问题的错误:https://github.com/golang/go/issues/30822

如果我在 dlopen 调用中添加标志 rtld_nodelete (dlopen("mylib.so", rtld_lazy | rtld_nodelete )),那么所有迭代都运行良好,但我不确定这是否是正确的做法。


正确答案


dlclose 不适用于 Go 共享库,并且已经是 an open issue since 2015。问题的根源似乎是 Go 没有提供方法来优雅地终止运行时可能已启动且可能仍在运行的任何后台线程在您致电 dlclose 时。

除了这个限制之外,dlclose 显然是 not required to do much of anything anyway

另请参阅 Using Go in C limitations

因此,看来您不妨通过使用 RTLD_NODELETE 来引起人们对库缺乏“可卸载性”的注意。

如果这是更通用的“插件”系统的一部分,您可以在其中使用多种不同语言编写的库,那么您可能不希望将 RTLD_NODELETE 应用于其中的全部。在这种情况下,您可以在创建共享库时尝试使用 -z nodelete 链接器选项。然后,调用 dlopen 的代码不需要了解它加载的任何特定 .so 文件的怪癖。 (有 code in Go to add that parameter automatically;我认为如果您使用 go 工具 link 进行链接而不是直接运行 gcc ,则会使用它。)

理论要掌握,实操不能落!以上关于《重复调用(dlopen)和取消加载(dlclose)同一共享对象导致段错误》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>