【问题标题】:Why symbols are unavailable in later dlopened .so file?为什么符号在以后的 dlopen .so 文件中不可用?
【发布时间】:2022-10-12 23:51:40
【问题描述】:

我正在尝试为this 问题建立一个解决方法。方法是将所有关于Python的代码移动到一个单独的so文件中,并制作一个loader来加载和运行它。在我看来,dlopen 应该将所有符号加载到默认命名空间中,然后我可以绕过命名空间问题。

这是 JNI 中的加载器:

extern "C" JNIEXPORT void JNICALL
Java_com_example_app_NativeLoader_load(
    JNIEnv* env,
    jobject /* this */,
    jstring jLibraryPath) {
    const char *libraryPath = env->GetStringUTFChars(jLibraryPath, NULL);

    void *handle = dlopen(libraryPath, RTLD_NOW|RTLD_GLOBAL);
    if (handle == nullptr) {
        LOGD("load %s failed: %s", libraryPath, dlerror());
        goto exit;
    }

    // The lib is loaded successfully
    // Then I should load the entry function, and run it.
    // But here is another test:
    void *sym = dlsym(handle, "PyExc_SystemError"); ///< this works

    void *handle_2 = dlopen("/some/path/to/_csv.cpython-310.so", RTLD_NOW);
    if (handle_2 == nullptr) {
        // !!! It goes here, but it shouldn't.
        LOGD("load _csv.cpython-310.so failed: %s", dlerror());
    }

exit:
    env->ReleaseStringUTFChars(jLibraryPath, libraryPath);
}

它确认PyExc_SystemError 在主库中,但是当我dlopen _csv.cpython-310.so 时,它说:

 03:57:17.744  3102  3102 D example: load /data/app/com.example.app-v4JTCukKIPJdXmBSnDMO6A==/base.apk!/lib/x86_64/_csv.cpython-310.so failed: dlopen failed: cannot locate symbol "PyExc_SystemError" referenced by "/data/app/com.example.app-v4JTCukKIPJdXmBSnDMO6A==/base.apk!/lib/x86_64/_csv.cpython-310.so"

运行环境为Android 9.0/10.0/11.0,NDK r25。为什么符号不可用?

【问题讨论】:

  • 哪个LOGD 产生了引用的错误消息?我认为这是第一个,因为第二个有不同的字符串文字。
  • 不,是第二个。第一次dlopen 加载成功。

标签: android android-ndk dlopen


【解决方案1】:

我想我知道为什么会这样。

当您显示 dlerror 时,它告诉 PyExc_SystemError 没有找到,所以我认为这是来自 dlsym 的错误消息,而不是来自第二个 dlopen。

我认为您的 dlsym 无法正常工作,您应该像这样测试良好的加载:

 
    // load the symbol
    typedef void (*func_loaded_type();

    // reset errors
    dlerror();
    func_loaded_type func_loaded = (func_loaded_type) dlsym(handle, "PyExc_SystemError");
    const char *dlsym_error = dlerror();
    if (dlsym_error) {
        cerr << "Cannot load symbol 'hello': " << dlsym_error <<
            '
';
        dlclose(handle);
        return 1;
    } 

如果我是对的,它应该进入 if 括号。它加载失败的原因可能是因为您在编写和编译您首先加载的 .so 文件时没有使用extern "C"

但你的另一个问题是“handle_2 == nullptr”是真的,它不应该。正如我之前假设的那样,显示的 dlerror 来自 dlsym,这可能是由于您没有重置 dlerror 造成的。为此,只需将dlerror(); 放在第二个 dlopen() 行之前。

有关更多信息,或者如果我错了,请查看此(关于 dlopen 的好教程)[https://tldp.org/HOWTO/C++-dlopen/intro.html]。它可能会减轻你的负担。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-19
    • 1970-01-01
    • 2020-01-30
    相关资源
    最近更新 更多