简体   繁体   中英

How to use shared library for Android NDK (C lib adding to C++)

So. I found this lib in C called fastpbkdf2 and made shared lib out of it.

I created small C++ snippet that'll call one of the methods from the lib. But I'm constantly getting

error: undefined reference to ...

I search for so many stuff, try everything, but no luck. I'm probably missing something obvious here. (oh, and I've never programmed for C++ or C so maybe that could be the problem)

All the files are in same folder.

Here's Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE           := pbkdf2core
LOCAL_SRC_FILES        := libpbkdf2core.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE    := pbkdf2
LOCAL_SRC_FILES := pbkdf2.cpp
LOCAL_SHARED_LIBRARIES := pbkdf2core
include $(BUILD_SHARED_LIBRARY)

Here's my try in C++:

#include <jni.h>
#include "native.h"
#include <pbkdf2core.h>

extern "C"{
    JNIEXPORT jbyteArray JNICALL Java_com_package_generatePBKDF2key
    (JNIEnv * env, jclass cls, jbyteArray password, jbyteArray salt, jint iterations)
    {
            uint8_t * out;

            fastpbkdf2HmacSha1(jbyteArrayToString(env, password), 
                env->GetArrayLength(password), 
                jbyteArrayToString(env, salt), 
                env->GetArrayLength(salt), 
                (int) iterations, out, 32);


            jbyteArray bytes = env->NewByteArray(32); 
            env->SetByteArrayRegion(bytes, 0, 32, (jbyte*)out); 
            return bytes;
            //return password; --> running only this works ok
    }

    uint8_t* jbyteArrayToString(JNIEnv* env, jbyteArray barr)
    {
           uint8_t* rtn = NULL;
           jsize alen = env->GetArrayLength(barr);
           jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
           if (alen > 0)
           {
                     rtn = (uint8_t*)malloc(alen + 1);
                     memcpy(rtn, ba, alen);
                     rtn[alen] = 0;
           }
           env->ReleaseByteArrayElements(barr, ba, 0);
           return rtn;
    }

    //commenting out "bad" code, and running only this really works
    JNIEXPORT jint JNICALL Java_com_package_getNum(JNIEnv * env, jclass cls){
        return 1;
    }
}

And pbkdf2core.h:

#include <jni.h>
#include <stdlib.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif
void fastpbkdf2HmacSha1(const uint8_t *pw, size_t npw,
                          const uint8_t *salt, size_t nsalt,
                          uint32_t iterations,
                          uint8_t *out, size_t nout);
#ifdef __cplusplus
}
#endif

When I skip the "bad" code, everything is ok (I can run the other method, or return anything from the first, so all the other setup should be ok).

If I change anything from header, I get different error (not declared). What am I missing here? (oh. the lib I'm using is in C.

Edit:

Here's error I get:

[armeabi] Compile++ thumb: pbkdf2 <= pbkdf2.cpp
[armeabi] SharedLibrary  : libpbkdf2.so
/Users/.../src/main/jni/pbkdf2.cpp:15: error: undefined reference to 'fastpbkdf2HmacSha1'
collect2: error: ld returned 1 exit status
make: *** [/Users/.../src/main/obj/local/armeabi/libpbkdf2.so] Error 1

Oh. I also tried with

LOCAL_ALLOW_UNDEFINED := true

Build does go ok (obviously), but then I get app runtime error:

java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "fastpbkdf2HmacSha1"

It looks like the linker cannot find the method fastpbkdf2HmacSha1, in your source code and the shared library. By forcing it to ignore the problem (eg using the LOCAL_ALLOW_UNDEFINED flag), you simple move the problem at runtime. That's why you get the UnsatisfiedLinkError (the VM tries to load the library, which has a missing dependency, and the loading fails).

First I would make sure that the library you are using is correct. You need to look into the libpbkdf2core.so for the missing symbol (fastpbkdf2HmacSha1). You can do this using readelf and nm. Nm will show you the symbols if you have a debug .so, whereas with readelf is a more powerful tool.

To get the symbol table from the .so do something like this:

readelf -Ws libpbkdf2core.so | grep fastpbkdf2HmacSha1

If the symbol is not there, you either have a corrupt .so or you are using the wrong .so?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM