Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shared library symbols not visible on dlopen()? #201

Closed
fornwall opened this issue Sep 18, 2016 · 3 comments
Closed

Shared library symbols not visible on dlopen()? #201

fornwall opened this issue Sep 18, 2016 · 3 comments
Assignees

Comments

@fornwall
Copy link

I have a shared library libshared.so containing a function libshared_get_value().

I also have a shared library libplugin.so, which does not link against libshared.so but references the extern function libshared_get_value()

Finally there is an executable linking against libshared.so. At runtime this executable tries to dlopen() the libplugin.so shared library.

This works on "normal" Linux (tested on Ubuntu 16.04).

This does not work on Android (tested on Android 5.0/arm and 6.0/aarch) but fails at runtime with the error message cannot locate symbol "libshared_get_value" referenced by "libplugin.so".

This difference in behaviour causes problems for things like perl and node, where extensions built as shared libraries expects symbols from already loaded libraries to be visible without needing to link against the libraries containing the symbols explicitly. See e.g. How To Link -lperl to Extensions During Build where the following is said:

Thanks to its broken linker, I need to link libperl.so with every extension that uses symbols from it.

Is the Android linker (or tools) really broken in this regard, or is the behaviour the expected/desired one?

See https://github.com/termux/shared-library-testcase for a small test case.

@dimitry-
Copy link
Contributor

tl;dr; This one of the not many differences between linux loader and android loader. On Android only the main executable and LD_PRELOADs are considered to be RTLD_GLOBAL, all the dependencies of the main executable remain RTLD_LOCAL.

Longer explanation:

ld-linux.so marks everything linked against main executable with RTLD_GLOBAL, this is why the example works on Linux. Android loader was not handling RTLD_GLOBAL correctly up until M release. It was fixed in M for things like dlopen/dlsym() but not for the dependencies of the main executable, because it lead to many compatibility problems.

Workaround:

Adding libshared.so dependency to libplugin.so should solve this problem and make the executable.

@dimitry- dimitry- self-assigned this Sep 19, 2016
@fornwall
Copy link
Author

@dimitry- Thanks a lot for the information!

I guess this issue can be closed here as it's not an NDK issue.

fornwall added a commit to termux/termux-packages that referenced this issue Mar 30, 2017
The pgsql extension uses pcre functions but does not link against
libpcre by default, as the php executable which dlopen():s the
extension already links against libpcre.

However, on Android this doesn't work, see
	android/ndk#201
so we need to link against libpcre explicitly.
its-pointless pushed a commit to its-pointless/termux-packages that referenced this issue May 7, 2017
The pgsql extension uses pcre functions but does not link against
libpcre by default, as the php executable which dlopen():s the
extension already links against libpcre.

However, on Android this doesn't work, see
	android/ndk#201
so we need to link against libpcre explicitly.
Kudo added a commit to Kudo/v8-android-buildscripts that referenced this issue Nov 7, 2019
Summary:
    On some Android device, there is libv8.so in system ROM.
    E.g. /system/lib/libv8.so or /vendor/lib/libv8.so

    On old Android, dlopen() with RTLD_GLOBAL is not handled well and it's by default RTLD_LOCAL.
    Even we call System.loadLibrary("v8") before,
    during the time RNV8 call System.loadLibrary("v8executor") and search libv8.so in DT_NEEDED.
    It seems bionic linker will use system libv8.so instead of ours.
    Since our libv8.so is customized with libplatform.so, this leads to unresolved symbol as
    Kudo/react-native-v8#29.

    That's why I am proposing to rename libv8.so as libv8android.so and to prevent name conflict from system libv8.so.

    Reference for RTLD_GLOBAL: android/ndk#201
Kudo added a commit to Kudo/react-native-v8 that referenced this issue Nov 7, 2019
Summary:
    On some Android device, there is libv8.so in system ROM.
    E.g. /system/lib/libv8.so or /vendor/lib/libv8.so

    On old Android, dlopen() with RTLD_GLOBAL is not handled well and it's by default RTLD_LOCAL.
    Even we call System.loadLibrary("v8") before,
    during the time RNV8 call System.loadLibrary("v8executor") and search libv8.so in DT_NEEDED.
    It seems bionic linker will use system libv8.so instead of ours.
    Since our libv8.so is customized with libplatform.so, this leads to unresolved symbol as
    #29.

    That's why I am proposing to rename libv8.so as libv8android.so and to prevent name conflict from system libv8.so.

    Reference for RTLD_GLOBAL: android/ndk#201
Kudo added a commit to Kudo/react-native-v8 that referenced this issue Nov 7, 2019
Summary:
    On some Android device, there is libv8.so in system ROM.
    E.g. /system/lib/libv8.so or /vendor/lib/libv8.so

    On old Android, dlopen() with RTLD_GLOBAL is not handled well and it's by default RTLD_LOCAL.
    Even we call System.loadLibrary("v8") before,
    during the time RNV8 call System.loadLibrary("v8executor") and search libv8.so in DT_NEEDED.
    It seems bionic linker will use system libv8.so instead of ours.
    Since our libv8.so is customized with libplatform.so, this leads to unresolved symbol as
    #29.

    That's why I am proposing to rename libv8.so as libv8android.so and to prevent name conflict from system libv8.so.

    Reference for RTLD_GLOBAL: android/ndk#201
Kudo added a commit to Kudo/react-native-v8 that referenced this issue Nov 7, 2019
Summary:
    On some Android device, there is libv8.so in system ROM.
    E.g. /system/lib/libv8.so or /vendor/lib/libv8.so

    On old Android, dlopen() with RTLD_GLOBAL is not handled well and it's by default RTLD_LOCAL.
    Even we call System.loadLibrary("v8") before,
    during the time RNV8 call System.loadLibrary("v8executor") and search libv8.so in DT_NEEDED.
    It seems bionic linker will use system libv8.so instead of ours.
    Since our libv8.so is customized with libplatform.so, this leads to unresolved symbol as
    #29.

    That's why I am proposing to rename libv8.so as libv8android.so and to prevent name conflict from system libv8.so.

    Reference for RTLD_GLOBAL: android/ndk#201

(cherry picked from commit 5a78dd5)
Kudo added a commit to Kudo/react-native-v8 that referenced this issue Nov 7, 2019
Summary:
    On some Android device, there is libv8.so in system ROM.
    E.g. /system/lib/libv8.so or /vendor/lib/libv8.so

    On old Android, dlopen() with RTLD_GLOBAL is not handled well and it's by default RTLD_LOCAL.
    Even we call System.loadLibrary("v8") before,
    during the time RNV8 call System.loadLibrary("v8executor") and search libv8.so in DT_NEEDED.
    It seems bionic linker will use system libv8.so instead of ours.
    Since our libv8.so is customized with libplatform.so, this leads to unresolved symbol as
    #29.

    That's why I am proposing to rename libv8.so as libv8android.so and to prevent name conflict from system libv8.so.

    Reference for RTLD_GLOBAL: android/ndk#201

(cherry picked from commit 5a78dd5)
@fahadali32
Copy link

I get some error

xtkoba added a commit to termux/termux-packages that referenced this issue Feb 7, 2022
nirbheek added a commit to nirbheek/meson that referenced this issue Feb 14, 2022
Android requires shared modules that use symbols from other shared
modules to be linked before they can be dlopen()ed in the correct
order. Not doing so leads to a missing symbol error:
android/ndk#201

We need to always allow linking for this. Also add a soname, although
it's not confirmed that it's needed, and it doesn't really hurt if it
isn't needed.
eli-schwartz pushed a commit to mesonbuild/meson that referenced this issue Feb 15, 2022
Android requires shared modules that use symbols from other shared
modules to be linked before they can be dlopen()ed in the correct
order. Not doing so leads to a missing symbol error:
android/ndk#201

We need to always allow linking for this. Also add a soname, although
it's not confirmed that it's needed, and it doesn't really hurt if it
isn't needed.
nirbheek added a commit to mesonbuild/meson that referenced this issue Mar 11, 2022
Android requires shared modules that use symbols from other shared
modules to be linked before they can be dlopen()ed in the correct
order. Not doing so leads to a missing symbol error:
android/ndk#201

We need to always allow linking for this. Also add a soname, although
it's not confirmed that it's needed, and it doesn't really hurt if it
isn't needed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants
@fornwall @dimitry- @fahadali32 and others