Monthly Archives: February 2012

Debugging shared library linking in Android

So Android does let you run command line utilties, but they sure don’t make it easy. I am currently building gnupg for Android, and for some of the binaries I got, they worked fine, others I got this when I ran them:

# ./gpg-agent
link_image[1995]: failed to link gpg-agent-static
CANNOT LINK EXECUTABLE

So my guess was that there was some missing shared libs, I checked that using readelf -d gpg-agent. All of the libraries listed were included in my setup and they were found once I did:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/data/data/info.guardianproject.gpg/app_opt/lib

And yet, I still got this error. My final hunch was that my binaries included some symbols which Android’s libs did not provide. But how could I find out which symbols were the problem? I discovered you can use ld, so I did:

hans@palatschinken lib $ adb pull /system/lib /tmp/system-lib
hans@palatschinken lib $ cp *.so* /tmp/system-lib
hans@palatschinken lib $ for so in *.so; do echo $so; arm-linux-androideabi-ld $so -rpath=/tmp/system-lib; done
libassuan.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008254
libgcrypt.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008258
libgpg-error.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008258
libksba.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008254
liblber.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008258
libldap_r.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008258
libldap_r.so: undefined reference to `pthread_rwlock_rdlock'
libldap_r.so: undefined reference to `pthread_rwlock_init'
libldap_r.so: undefined reference to `pthread_rwlock_destroy'
libldap_r.so: undefined reference to `pthread_rwlock_unlock'
libldap_r.so: undefined reference to `pthread_rwlock_wrlock'
libldap_r.so: undefined reference to `pthread_rwlock_trywrlock'
libldap_r.so: undefined reference to `pthread_rwlock_tryrdlock'
libldap.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008258
libnpth.so
arm-linux-androideabi-ld: warning: cannot find entry symbol _start; defaulting to 00008254

And voila! There were the symbols in question. Indeed, Android does not provide pthread_rwlock_*.


which macros does the Android NDK gcc define?

I’m working with a lot of cross-platform C code these days, and I find that when porting, its always best to use the macros that are automatically defined by the compiler for that platform. I’ve gotten very used to using __APPLE__ and _WIN32 (arg, yes, not WIN32 as we’d like it), then of course there is __gnu_linux__ for the OS and __linux__ for the kernel. No this is not RMS polemics, this is important, especially since there is now Debian GNU (with a Hurd kernel) and Debian GNU/kFreeBSD (no Linux there). And of course, the main feature of this post: Android.

Android uses the Linux kernel, but is definitely not GNU. The only GNU part of Android I’ve seen is the compiler: gcc.

So what macros does the Android gcc define? I wanted to know, so I ran a little test:

#include 

int main(void)
{
#ifdef __ANDROID__
    printf("__ANDROID__\n");
#endif
#ifdef ANDROID
    printf("ANDROID\n");
#endif
#ifdef android
    printf("android\n");
#endif
#ifdef __linux__
    printf("__linux__\n");
#endif
#ifdef __gnu_linux__
    printf("__gnu_linux__\n");
#endif
}

I ran that thru the cpp by running /usr/local/android-ndk/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc --sysroot=/usr/local/android-ndk/platforms/android-8/arch-arm/ -E -o /tmp/test.E /tmp/test.c and got:

...[snip]
int main(void)
{

    printf("__ANDROID__\n");
# 15 "/tmp/test.c"
    printf("__linux__\n");




}


Follow

Get every new post delivered to your Inbox.