How can I tell which runtime an Android .so was compiled with?

2k views Asked by At

I have some pre-compiled so files, so who knows what flags were used to generate them. I'm curious to know which runtime/version of the STL they were compiled with (gnustl_shared? stlport_shared?) to avoid clashes with my own code.

How can I find out from the compiled so files which runtime they were compiled to use?

This is all Android NDK C++ code.

2

There are 2 answers

2
Alex Cohn On BEST ANSWER

NDK comes with a utility named readelf (under NDK/toolchains). To see which shared STL library is needed for a prebuilt binary, you can run

$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/*/bin/arm-linux-androideabi-readelf -a 3rd-party-lib.so | grep NEEDED | grep _shared

Version is tricky. The STL shared binaries ship without version information, and I don't believe there exists a process that tests their backwards compatibility. Still, both stlport abd gnustl have been stable for at least two years now.

You can usually determine what compiler was used to build the binary, but no, NDK compilers are not always changed with each NDK release.

3
Dan Albert On

Like Alex said, you can use readelf to figure out some of this. The following can let you know if the library depends on a shared STL, and which one:

$ readelf -dW path/to/libfoo.so | grep NEEDED
 0x00000001 (NEEDED)                     Shared library: [libc++_shared.so]
 0x00000001 (NEEDED)                     Shared library: [libc.so]
 0x00000001 (NEEDED)                     Shared library: [libm.so]
 0x00000001 (NEEDED)                     Shared library: [libstdc++.so]
 0x00000001 (NEEDED)                     Shared library: [libdl.so]

As you can see, this library depends on libc++_shared. Ignore the libstdc++.so that you also see. That's https://github.com/android-ndk/ndk/issues/105.

If it depends on a static STL (or your library is a static library) and wasn't built with -fvisibility=hidden, that method won't work. In this case you can still identify if the library was built against libc++ or not-libc++. All the libc++ symbols are in an internal namespace (std::__ndk1 instead of just std) to support versioning the STL and avoiding clashes with the system STL. If it's a very old (r10 or older) libc++, it will be just __1.

$ readelf -sW path/to/libfoo.so | grep __ndk1
     6: 000008bf    86 FUNC    WEAK   DEFAULT   12 _ZNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcj
     7: 000008a9    22 FUNC    WEAK   DEFAULT   12 _ZNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED2Ev

If you're trying to figure out which version of the NDK a library was built with, you can use https://android.googlesource.com/platform/ndk/+/master/parse_elfnote.py.

$ python parse_elfnote.py foo/libs/armeabi-v7a/libfoo.so 
----------ABI INFO----------
ABI_NOTETYPE: 1
ABI_VENDOR: Android
ABI_ANDROID_API: 14
ABI_NDK_VERSION: r17-canary
ABI_NDK_BUILD_NUMBER: dev

Most of this information will only be available for libraries built with a relatively new NDK (r14? I don't remember when we added this).