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

undefined reference with ndk r12 #126

Closed
1bsyl opened this issue Jun 19, 2016 · 42 comments
Closed

undefined reference with ndk r12 #126

1bsyl opened this issue Jun 19, 2016 · 42 comments

Comments

@1bsyl
Copy link

1bsyl commented Jun 19, 2016

I have updated from NDK r11c to r12 and there are some missing references when loading my shared library:
(at least):
00000000 DF UND 00000000 LIBC_N __aeabi_memclr4
00000000 DF UND 00000000 LIBC_N __aeabi_memmove
00000000 DF UND 00000000 LIBC_N __aeabi_memclr8
00000000 DF UND 00000000 LIBC_N __aeabi_memcpy
00000000 DF UND 00000000 LIBC_N __aeabi_memcpy4
00000000 DF UND 00000000 LIBC_N __aeabi_memclr
00000000 DF UND 00000000 LIBC_N __aeabi_memset
00000000 DF UND 00000000 LIBC_N __aeabi_atexit

@dimitry-
Copy link
Contributor

Looks like you are targeting 24 but running on previous version of android.

@1bsyl
Copy link
Author

1bsyl commented Jun 19, 2016

Yes, I was about to write the solution, I am using targetSdkVersion=24 on a lower device.

@1bsyl 1bsyl closed this as completed Jun 19, 2016
@1bsyl
Copy link
Author

1bsyl commented Jun 19, 2016

I reopen to have more feedback:

With (compileSdkVersion=24, targetSdkVersion=23), it runs.
But it requires to install both SDK Platform 23 & 24. Why, since I specified "compileSdkVersion=24", I would expect to download and need only the package "Android N (API 24) SDK Plaform" ?

According to:
http://stackoverflow.com/questions/26694108/what-is-the-difference-between-compilesdkversion-and-targetsdkversion

I should be able to bump "targetSdkVersion" to 24, but it fails to run because of undefined reference (at least "__aeabi_memclr4"). Doesn't seem to be an API thing, but more low level library issue ?

Signification of {min,max,target, compile}SdkVersion is quite blur ... (for years)

@1bsyl 1bsyl reopened this Jun 19, 2016
@DoDoENT
Copy link

DoDoENT commented Jun 29, 2016

Also happens to us, but only for armeabi-v7a target on some devices (HTC One M8, Android 6.0; SGS5; Android 6.0). It is weird that it does not happen on SGS4, Android 5.0.1 nor on Huawei P8Lite, Android 5.0.1. It also does not happen on arm64-v8a on SGS6, Android 6.0.

@DoDoENT
Copy link

DoDoENT commented Jun 29, 2016

Confirmed that setting target=android-23 works. Are there any known workarounds to make it work when targeting android-24? We had similar issue when upgrading from android-19 to android-21 in order to be able to use GLES3 on compatible devices - some functions used to be defined in headers in android-19 platform and were moved to lib in android-21 - therefore we needed to implement those functions in our code.

@DoDoENT
Copy link

DoDoENT commented Jun 29, 2016

Where are these functions defined?

$ grep -rIn __aeabi_memclr4 .

finds nothing.

@dimitry-
Copy link
Contributor

I think there is confusion between targetSdkVersion and LOCAL_SDK_VERSION

NDK interpretation of LOCAL_SDK_VERSION is minimum SDK version - which means that it is not guaranteed to work on devices with sdk < LOCAL_SDK_VERSION.

I am not sure how targetSdkVersion gets propagated to LOCAL_SDK_VERSION - do you use gradle to build native libraries?

(You are getting this error because if LOCAL_SDK_VERSION is set to 24 these symbols get LIBC_N version. These symbols were mistakenly versioned as LIBC_PRIVATE instead of LIBC in android-23 which was fixed in 24, hence the symbol version mismatch if you try to run load the library linked against libc.so from android-24 on android-23)

@1bsyl
Copy link
Author

1bsyl commented Jun 29, 2016

@DoDoENT
I believe this is used implicitly, when application uses "memset", or maybe when initializing some array. You linked (statically) with the libc of the targeted sdk.

Then, calling objdump -T on my shared library displays:

targetSdkVersion 24:
00000000 DF *UND* 00000000 LIBC_N __aeabi_memclr4

targetSdkVersion 23:
00000000 DF *UND* 00000000 __aeabi_memclr4

I use gradle, but with some ndk commands so that it seems equivalent to calling ndk-build
(with command line option APP_PLATFORM=android-24)

My build.gradle contains
targetSdkVersion 23 (or 24, which leads to the issue)
compileSdkVersion 24

AndroidManifest.xml, my minSdkVersion is 10.

According to : https://developer.android.com/guide/topics/manifest/uses-sdk-element.htm

android:targetSdkVersion

An integer designating the API Level that the application targets. If not set, the default value equals that given to minSdkVersion.

This attribute informs the system that you have tested against the target version and the system should not enable any compatibility behaviors to maintain your app's forward-compatibility with the target version. The application is still able to run on older versions (down to minSdkVersion).

@DoDoENT
Copy link

DoDoENT commented Jun 29, 2016

@1bsyl, I was referring to APP_PLATFORM NDK parameter - it has to be set to android-23 or lower. Nevertheless, in your build.gradle you can target API level 24 (it is used only for Java code).

@1bsyl
Copy link
Author

1bsyl commented Jun 29, 2016

In fact, the safest, is to set APP_PLATFORM to the minSdkLevel ?
And to keep other "targetSdkVersion" and "compileSdkVersion" to 24.

@DoDoENT
Copy link

DoDoENT commented Jun 29, 2016

@1bsyl indeed, unless you need to use some NDK features available only in later API levels (like for example GLES3 on compatible devices, while falling back to GLES2 on older devices - in order to access GLES3 headers, you need APP_PLATFORM=android-21 or later, which produces binary which is not so compatible with KitKat and earlier Android versions).

@1bsyl
Copy link
Author

1bsyl commented Jun 29, 2016

@DoDoENT
Ok! your example totally makes sense.

And, bumping targetSdkVersion to 24 in build.gradle and AndroidManifest.xml, can it have some bad side effect ? (while keeping a lower APP_PLATFORM for the ndk side).

@DoDoENT
Copy link

DoDoENT commented Jun 29, 2016

@1bsyl from our experience at MicroBlink we recommend having compileSdkVersion always set to latest stable API level (currently this is 24), targetSdkVersion set to latest API level with which you have extensively tested your app (for us this is still 23, as we cannot test with 24 because Android N is still not released - bugs and failures on preview versions can be attributed to both bugs in your app as well as bugs in platform itself - this is why we usually wait for Google to release official build of new Android version and then we test on it) and minSdkVersion set to minimum API level your app supports (for us this is still 10 :-( ).

One example where you may put your targetSdkVersion to 21, while using compileSdkVersion on 24 would be case when you have not implemented Android M permission model in your app. Similarly, if you have not prepared your app to work in multi-window environment introduced in Android N (will it be called Nutella?) you should not set targetSdkVersion to 24 (setting it so would mean that you have tested your app in multi window environment and this feature will be enabled for your app on devices running Android N).

On NDK side, you should set APP_PLATFORM to same as minSdkVersion in build.grade to be absolutely sure your app will work correctly. However, if you need NDK features that were introduced in later API levels, you should set APP_PLATFORM to minimum API level which gives a feature you need and then test intensively on lower API levels to ensure everything works (this may require some weird hacks to ensure binary built with APP_PLATFORM=android-23 to work on Gingerbread :-P ).

@DanAlbert
Copy link
Member

unless you need to use some NDK features available only in later API levels (like for example GLES3 on compatible devices, while falling back to GLES2 on older devices - in order to access GLES3 headers, you need APP_PLATFORM=android-21 or later

@DoDoENT: Just to confirm, the reason you can do this with GL is because you're not actually linking against any symbols introduced in android-21, but using eglGetProcAddress to get the function pointer to the API and only using it if it's available? AIUI that's what's going on here, but I don't actually do any GL programming myself so I wanted to confirm.

If that's the case then we'll actually have a solution for you fairly soon (if not r13 than r14). We're working on unifying our headers so there's only one version of the headers for every API level, and things that need to be guarded by API level will just have the appropriate attributes/ifdefs to hide them as needed. All the GL constants could be exposed for every platform level though. See #120.

@DanAlbert
Copy link
Member

As for the main bug here, as @dimitry- says, it looks like you're trying to run below your minimum platform version. Nothing we can do to fix that problem without a time machine :)

@1bsyl
Copy link
Author

1bsyl commented Jun 29, 2016

@DoDoENT
Thanks again, for your second very clear explanation !

@DanAlbert
No need for a time machine, I can choose to bump the "app_platform" without changing my application, that would be backward compatibility :)

In fact, it's not failing because of a missing function as reported initially. In both case, "__aeabi_memclr4" function is needed. As @dimitry- said, in the new android-24 version, the symbol get marked as "LIBC_N", and the issue is that the loader will fail to find this function on an older platform (eg android-23).

Just emphasize the use-case that will be - in the future - problematic:
as @DoDoENT explains, we can want to bump the APP_PLATFORM to have the possibility to use more functions on platforms that provide them. Eg dlopen(GLES3) and use it if it exists, or fall-back to GLES2.

If a new set of API appears (an extension of GLES3 for instance) and you want to use it, you can choose to bump the app_platform, and use the same trick of dlopen+fallback. But for now on, it will fail on older platform, because of the LIBC_N symbols.

I think that's going to be the issue ...

@DoDoENT
Copy link

DoDoENT commented Jun 30, 2016

@DoDoENT: Just to confirm, the reason you can do this with GL is because you're not actually linking against any symbols introduced in android-21, but using eglGetProcAddress to get the function pointer to the API and only using it if it's available? AIUI that's what's going on here, but I don't actually do any GL programming myself so I wanted to confirm.

Exactly. We use android-21 headers because they define constants like EGL_OPENGL_ES3_BIT and GL_UNPACK_ROW_LENGTH and function glPixelStorei which is the only function we currently use that is specific to GLES3 - those all are defined in GLES3/gl3.h which does not exist in android-9 platform (which we would use instead of android-21).

If that's the case then we'll actually have a solution for you fairly soon (if not r13 than r14). We're working on unifying our headers so there's only one version of the headers for every API level, and things that need to be guarded by API level will just have the appropriate attributes/ifdefs to hide them as needed. All the GL constants could be exposed for every platform level though.

Wow! I am looking forward to that.

@1bsyl
Copy link
Author

1bsyl commented Jun 30, 2016

@DanAlbert: Something which confused me also. And you explained it on android-ndk: The "target" API level for the NDK is not the same as in Java. It's the minimum API level you want to run on.

Currently, if APP_PLATFORM is not set, it picks automatically the targetSdkVersion of the AndroidManifest.xml.
It would be better to pick the "minSdkVersion".
Otherwise, there are the potential failures on all platform between "minSdkVersion" and "targetSdkVersion - 1".

@tgraupmann
Copy link

I had to move the native code to its own module with a min SDK, target SDK, and compile tools set to API 21 in order to get the native library to load properly. This started happening after upgrading to android-ndk-r12b. This is because __aeabi_atexit could not be found.

@DanAlbert
Copy link
Member

Currently, if APP_PLATFORM is not set, it picks automatically the targetSdkVersion of the AndroidManifest.xml.
It would be better to pick the "minSdkVersion".
Otherwise, there are the potential failures on all platform between "minSdkVersion" and "targetSdkVersion - 1".

Sorry, missed this before. Which build system is doing this? I agree, that's the wrong default.

@1bsyl
Copy link
Author

1bsyl commented Dec 10, 2016

Thanks for answering anyway! This is "ndk-build" of r13 from command line, on linux 64 bits.

Though, there is a warning "Android NDK: WARNING: APP_PLATFORM android-23 is larger than android:minSdkVersion 10 in ./AndroidManifest.xml".

my manifest is:

jonpryor added a commit to jonpryor/xamarin-android that referenced this issue Aug 31, 2017
Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=58029

Scenario: Build a project with:

  * `$(Configuration)`=Release
  * `$(AotAssemblies)`=True
  * `$(EnableLLVM)`=True
  * `$(TargetFrameworkVersion)`=v7.1 (API-25)
  * `//uses-sdk/@android:minSdkVersion`=10 (in `AndroidManifest.xml`)
  * with Android NDK r12b or later
  * on particular hardware devices, e.g. a Nexus 5.

Actual results: the app runs, but the AOT'd images aren't used:

	AOT: image 'Xamarin.Android.Support.v7.AppCompat.dll.so' not found: dlopen failed: cannot locate symbol "__aeabi_memset" referenced by "/data/app/com.companyname.App1-1/lib/arm/libaot-Xamarin.Android.Support.v7.AppCompat.dll.so"...

The `__aeabi_memset` symbol can't be found, preventing e.g.
`Xamarin.Android.Support.v7.AppCompat.dll.so` from being used. Meaning
the app pays the build overhead and size penalty of AOT+LLVM, but
doesn't get anything out of it; only the JIT is used.

The [cause of the missing `__aeabi_memset` symbol][0] is that we're
using the NDK paths which corresponds with `$(TargetFrameworkVersion)`,
*not* the NDK paths which correspond with
`//uses-sdk/@android:minSdkVersion`. Because of this, if you use the
`.apk` on a platform which is >= `minSdkVersion` but less than
`$(TargetFrameworkVersion)`, the AOT images won't be used.

[0]: android/ndk#126

Fix this by updating the `<Aot/>` task to instead use the
`//uses-sdk/@android:minSdkVersion` value. This ensures that we use
NDK paths which correspond to the app's minimum supported API level,
which should allow the AOT images to be loaded on downlevel devices.
@ajunkala
Copy link

ajunkala commented Oct 6, 2017

So uh... is there like a way to workaround this issue? I am having this issue and the only comments resembling a solution do not actually work.

Bumping compileSdkVersion/targetSdkVersion beyond 23 results in devices (and emulators) with an armv7a chipset running 23 or lower crashing with errors like:
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__aeabi_memcpy4" referenced by

@ajunkala
Copy link

ajunkala commented Oct 6, 2017

May be worth noting that I am using gradle so the whole "TODO: No idea" isn't exactly helpful.

@DanAlbert
Copy link
Member

@ajunkala
Copy link

ajunkala commented Oct 6, 2017

Found the solution. You can set the NDK target version with

android.ndk {
platformVersion = "19"
}

@DanAlbert
Copy link
Member

Is platformVersion the thing it uses? I'm not a gradle user so I don't know how to configure it, but whatever gradle is using for your NDK API level needs to match your minSdkVersion.

@ajunkala
Copy link

ajunkala commented Oct 6, 2017

That seems to be the case. Like I noted, I can repro the issue even w/ an emulator. I just added it and the issue seems to be resolved now.

@Rajveer86
Copy link

@DanAlbert Sorry to bring up an old issue, however I am experiencing exactly what you described here (relating to this).

I have an OpenGL ES 3.0 project which supports devices on KitKat (API 19) and have the following configuration:

compileSdkVersion = 26
minSdkVersion 19
targetSdkVersion 26

cmake {
    arguments '-DANDROID_PLATFORM=android-19', '-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=c++_static'
}

with #include <GLES3/gl3.h> used for including the OpenGL ES header.

I now want to use some 3.1 and 3.2 functions on devices that support them so have modified ANDROID_PLATFORM to DANDROID_PLATFORM=android-24 and my header include to #include <GLES3/gl32.h>. This (correctly) leads to my Android 5.0 (API 21) test device failing to load my native library with the error:

dlopen failed: cannot locate symbol [insert new 3.1/3.2 function name here]

I have no problem with finding whether these newer functions exist at runtime using eglGetProcAddress, however after reading your comment on unified headers (specifically the second paragraph about it being made easier) is this still the recommended way or is there an easier one?

@enh
Copy link
Contributor

enh commented Mar 23, 2018

eglGetProcAddress is still the recommended way. danalbert was just saying that unified headers mean that you'll have the <GLES3/gl3.h> header available even if you're targeting an API level that predates that header.

@Rajveer86
Copy link

I see, that makes perfect sense. Thank you for the quick reply, I'll go ahead with that route then :)

gmaclennan added a commit to digidem/mapeo-mobile that referenced this issue Apr 30, 2019
Switching targetSDK to 23 from 27 seems to fix the error.
Error: dlopen failed: cannot locate symbol "__aeabi_memcpy" referenced by "/data/data/com.mapeo.debug/files/nodejs-project/node_modules/leveldown/build/Release/leveldown.node"
See android/ndk#126
and https://android-review.googlesource.com/c/platform/bionic/+/195350
@neevek
Copy link

neevek commented May 20, 2019

Sorry to bring this up again, but how do I resolve the issue if I have to target 28 and support devices starting from 21? I am using NDK r19c.

dlopen failed: cannot locate symbol "__aeabi_memclr8" 

@DanAlbert
Copy link
Member

Stop doing that. Your NDK API level is your minSdkVersion.

@neevek
Copy link

neevek commented May 20, 2019

If I set the NDK API level to 21, it failed with 718

undefined reference to 'globfree'

which was fixed in r17b. Now this is a dead end to me.

@enh
Copy link
Contributor

enh commented May 20, 2019

If I set the NDK API level to 21, it failed with 718

undefined reference to 'globfree'

which was fixed in r17b. Now this is a dead end to me.

it's a mistake to think that globfree() was "fixed" in r17b. glob() and globfree() were added in API 28. you cannot use them in an app that needs to run on earlier OS versions.

(a workaround is to copy the source from bionic in AOSP into your app's source.)

@Yaakushi
Copy link

I know this is an old and closed issue for an older version of the NDK, and I apologize for posting here, but I'm going through the exact same issue (java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "__aeabi_memclr8" referenced by "libtwampc.so"... on devices running androud 4.x), and I'm fairly confident that I got the right API level (but I could be wrong).

I'm compiling using a standalone toolchain, and my environment setup currently looks like this:

export ARCHITECTURE=armv7a-linux-androideabi
export API_LEVEL=16

export NDK_VERSION=20.1.5948944
export NDK=$HOME/Android/Sdk/ndk/$NDK_VERSION/
export HOST_TAG=linux-x86_64

export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/$HOST_TAG
export AR=$TOOLCHAIN/bin/${ARCHITECTURE}-ar
export AS=$TOOLCHAIN/bin/${ARCHITECTURE}-as
export CC=$TOOLCHAIN/bin/${ARCHITECTURE}${API_LEVEL}-clang
export CXX=$TOOLCHAIN/bin/${ARCHITECTURE}${API_LEVEL}-clang++
export LD=$TOOLCHAIN/bin/${ARCHITECTURE}-ld
export RANLIB=$TOOLCHAIN/bin/${ARCHITECTURE}-ranlib
export STRIP=$TOOLCHAIN/bin/${ARCHITECTURE}-strip

And my CPPFLAGS looks like this:

export CPPFLAGS='-g -fPIC -DANDROID_PLATFORM=android-16 -DAPP_PLATFORM=android-16 -D__ANDROID_API__=16'

(I've added the defines for ANDROID_PLATFORM, __ANDROID_API__, and APP_PLATFORM after going through a few similar issues, but they did absolutely nothing for me)

As far as I understand, I'm compiling my binary for anything at API level 16 or above, and yet, it consistently crashes with devices running android 4.x (e.g. 4.3, 4.4.2, all running under armeabi-v7a). Am I overlooking something? Am I doing something stupid? Or is this really an issue?

@DanAlbert
Copy link
Member

Are those flags what you're using to build libtwampc.so? Or is that a prebuilt and it's just a dependency of what you're building?

@Yaakushi
Copy link

Sorry for forgetting such a crucial detail. Those are the flags I'm using to build libtwampc.so and another library used by libtwampc as a dependency. I can load the dependency library just fine, even in the devices where trying to load libtwampc.so fails.

@DanAlbert
Copy link
Member

Could you file a new bug with the readelf -sW $LIBRARY | grep __aeabi_memclr8 output for each of your libraries?

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

12 participants