Android NDK r5b external build and supc++ link problem - android-ndk

I am attempting to cross-compile our C++ code base (using CMake) for the Android platform using the r5b NDK on Ubuntu 10.10. The compile phase succeeds, however during the final link phase for the .so there are many unresolved references to symbols that are in the libsupc++.a file (which I specify to link in). I have also tried -lsupc++ with no difference.
I tried to follow the command-line as closely as possible as generated by the official ndk-build system when building the test-gnustl-1 NDK test app.
Running the arm-linux-androideabi-nm tool on the arm-linux-androideabi/lib/libsupc++.a file shows the symbols as defined (T) referenced in the error output.
An example of a symbol defined in libsupc++ it cannot find is: __gxx_personality_v0
Here is my sample link line and a resulting sample of errors.
/home/user/android-ndk-r5b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-g++ -fPIC -Wall -Wextra -Wno-unused -Wno-multichar -fno-rtti -MMD -MP -MF -ffunction-sections -fexceptions -funwind-tables -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -Wa,--noexecstack -DANDROID -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -O0 -DDEBUG -D_DEBUG -g --sysroot=/home/user/android-ndk-r5b/platforms/android-9/arch-arm -Wl,--gc-sections -Wl,-z,nocopyreloc -Wl,--no-undefined,-z,noexecstack -L/home/user/android-ndk-r5b/platforms/android-9/arch-arm/usr/lib -L/home/user/android-ndk-r5b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/arm-linux-androideabi/lib -Wl,-rpath-link=/home/user/android-ndk-r5b/platforms/android-9/arch-arm/usr/lib /home/user/android-ndk-r5b/sources/cxx-stl/gnu-libstdc++/libs/armeabi/libstdc++.a -lc -lsupc++ -shared -o ../../lib/Debug/libFoo.so CMakeFiles/Foo.dir/Foo.c.o CMakeFiles/Foo.dir/Bar.cpp.o CMakeFiles/Foo.dir/Baz.cpp.o
`CMakeFiles/Foo.dir/Foo.cpp.o: In function 'myFunc':
/home/user/myroj/src/native/modules/libFoo/Foo.cpp:292: undefined reference to '__cxa_end_cleanup'
CMakeFiles/Foo.dir/Foo.cpp.o:(.ARM.extab.text.myFunc+0x0): undefined reference to '__gxx_personality_v0'
...
/home/user/android-ndk-r5b/toolchains/android/sources/cxx-stl/gnu-libstdc++/include/bits/vector.tcc:350: undefined reference to '__cxa_begin_catch'
/home/user/android-ndk-r5b/toolchains/android/sources/cxx-stl/gnu-libstdc++/include/bits/vector.tcc:357: undefined reference to '__cxa_rethrow'
/home/user/android-ndk-r5b/toolchains/android/sources/cxx-stl/gnu-libstdc++/include/bits/stl_vector.h:1153: undefined reference to 'std::__throw_length_error(char const*)'
/home/user/android-ndk-r5b/toolchains/android/sources/cxx-stl/gnu-libstdc++/include/bits/stl_tree.h:199: undefined reference to 'std::_Rb_tree_decrement(std::_Rb_tree_node_base*)'
...
I tried to creating a simple hello-world app that makes use of exceptions and links in a simple .a file. I got the same errors until I linked in the libsupc++.a library directly instead of using '-lsupc++'. However, this same technique did not work on the larger project link step. The NDK docs also suggest '-lsupc++' is should be used when using external build tools.
I am out of ideas on how to resolve this linking issue. I have tried reordering the link line as many ways as I could think of. I know linking in general can be a fickle process.
Any help is greatly appreciated.

It turns out I needed to add -L/home/user/android-ndk-r5b/sources/cxx-stl/gnu-libstdc++/libs/armeabi" to the path and explicitly link "/home/user/android-ndk-r5b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/arm-linux-androideabi/lib/thumb/libsupc++.a" with all include libraries wrapped in a "--start-group --end-group" clause.
Hopefully this helps someone else too.

Related

Undefined symbol: fstat in dynamic library

I'm writing a dynamic library that's loaded at runtime as a plugin. At runtime, the library fails to load with the following message:
dlerror:/path/to/so: undefined symbol: fstat
The dynamic library consists of a bunch of static libraries linked together, including libsodium. I've tracked down libsodium as the only place that fstat() is used in the library.
As I understand it, fstat() should be part of libc, and should not require additional libraries to be installed. What am I missing?
EDIT1:
I've found some additional information about how linking to fstat() is different than most functions, but I'm not sure exactly how it applies to my situation. I am compiling/linking libsodium with the provided makefiles for their distribution, and the dynamic library is being compiled with the compiler driver as recommended in that answer.
EDIT2: here's the linker command, generated by CMake:
/usr/bin/c++ -fPIC -O3 -DNDEBUG -rdynamic -nodefaultlibs -undefined_warning -fPIC -fvisibility=hidden -shared -Wl,-soname,lin.xpl -o src/xplane_plugin/lin.xpl src/path/to/object/file1.cpp.o src/path/to/object/file2.cpp.o src/plugin/libplugin.a /usr/local/lib/libpng16.a -lz src/plenty/of/dependencies.a lib/glew/libglew.a src/another/library.a /usr/local/lib/libsodium.a /usr/lib/x86_64-linux-gnu/libcurl.so lib/json11/libjson11.a -lpthread deps/some/library.a /usr/local/lib/libzip.a -lbz2 -llzma -lssl -lcrypto -lstdc++fs -lz

Link problem when using address sanitizer with android NDK

I'm using Android Studio to build an app containing a module that uses the NDK. There is evidence of memory corruption so I'm trying the Address Sanitizer, following these instructions on the NDK developer site. But the app won't build.
I need to (A) ensure I'm targeting Android 27+ (I set minSdkVersion to 27; I'm building a debug build for a Galaxy S9, SDK 28), and (B) add compiler flags, which I've done:
android {
defaultConfig {
externalNativeBuild {
cmake {
# Can also use system or none as ANDROID_STL.
arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_STL=c++_shared"
cppFlags "-fsanitize=address -fno-omit-frame-pointer"
}
}
}
}
I've also added wrap.sh scripts according to the instructions but I understand that they become relevant only at runtime.
The problem is that my app won't build. The output follows.
The C++ compiler
"C:/Users/user/AppData/Local/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/windows-x86_64/bin/clang++.exe"
is not able to compile a simple test program.
It fails with the following output:
Change Dir:
C:/Users/user/studio/app/android/audioengine/.externalNativeBuild/cmake/debug/arm64-v8a/CMakeFiles/CMakeTmp
Run Build
Command:"C:\Users\user\AppData\Local\Android\sdk\cmake\3.6.4111459\bin\ninja.exe"
"cmTC_58655"
[1/2] Building CXX object
CMakeFiles/cmTC_58655.dir/testCXXCompiler.cxx.o
[2/2] Linking CXX executable cmTC_58655
FAILED: cmd.exe /C "cd . &&
C:\Users\user\AppData\Local\Android\sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe
--target=aarch64-none-linux-android27 --gcc-toolchain=C:/Users/user/AppData/Local/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/windows-x86_64
--sysroot=C:/Users/user/AppData/Local/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/windows-x86_64/sysroot
-g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -fno-addrsig -Wa,--noexecstack -Wformat -Werror=format-security -stdlib=libc++ -fsanitize=address -fno-omit-frame-pointer -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined -Qunused-arguments -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--gc-sections CMakeFiles/cmTC_58655.dir/testCXXCompiler.cxx.o -o cmTC_58655 -latomic -lm && cd ."
C:/Users/user/AppData/Local/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/windows-x86_64/lib/gcc/aarch64-linux-android/4.9.x/../../../../aarch64-linux-android/bin\ld:
warning: liblog.so, needed by
C:\Users\tim\AppData\Local\Android\sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\8.0.2\lib\linux\libclang_rt.asan-aarch64-android.so,
not found (try using -rpath or -rpath-link)
clang++.exe: error: linker command failed with exit code 1 (use -v
to see invocation)
The compiler flags have been passed correctly. There is a warning concerning liblog.so not being found, but then a non-specific error.
The instructions show where to place the sanitizer libraries in the project (in the jniLibs folder), but not where to source them. I copied them from the NDK install on my machine. I tried doing the same with liblog libraries but It's not clear which variant to use; the one I tried (for SDK 28) didn't affect the result.
What am I missing? I've found posts struggling with understanding exactly how to use the address sanitizer, but none mentions this particular problem.
Looks like those docs are wrong. It seems that CMake isn't using all of the linker flags it needs when performing that test. I'm not sure if that's NDK bug or a CMake bug, but here's a way to make ASan work with CMake/gradle:
Remove the cppFlags section from your build.gradle
Add those options in your CMakeLists.txt instead, like so:
add_library(app SHARED app.cpp)
target_compile_options(app PUBLIC -fsanitize=address -fno-omit-frame-pointer)
set_target_properties(app PROPERTIES LINK_FLAGS -fsanitize=address)
I've uploaded a change to fix the docs. Should be live soon.

relocation R_X86_64_PC32 against symbol _ZTISt13runtime_error##GLIBCXX_3.4 can not be used when making a shared object; recompile with -fPIC

The project I am attempting compile is not in any way complex, and references nothing but the standard library and one self-contained library (everything compiles fine on another system). As indicated by the title, it can't even link against something in the standard library, due to things in there not having been compiled with -fPIC, supposedly. I didn't build it myself, nor do I want to, and reinstalling things with apt didn't seem to resolve the "recompile with -fPIC" issue.
I will say that I think one possible source of the issue is due to gcc-multilib or something being installed earlier, but I think that was purged. I don't know, maybe something was overwritten or a conflict arose. Might not even be related. Any ideas?
Running Ubuntu 18.04
g++ -I inc -I /usr/include/mono-2.0 -MMD -MF dep/Nonsense.d -std=c++17 -O3 -fno-stack-protector -fno-unroll-loops -fomit-frame-pointer -Wno-ignored-optimization-argument -c -o obj/Nonsense.o src/Nonsense.cpp
g++ -I inc -I /usr/include/mono-2.0 -MMD -MF dep/Socket.d -std=c++17 -O3 -fno-stack-protector -fno-unroll-loops -fomit-frame-pointer -Wno-ignored-optimization-argument -c -o obj/Socket.o src/Socket.cpp
g++ -shared -flto -o libNonsense.so obj/Nonsense.o obj/Socket.o -Llib -lenet
/usr/bin/x86_64-linux-gnu-ld: obj/Socket.o: relocation R_X86_64_PC32 against symbol `_ZTISt13runtime_error##GLIBCXX_3.4' can not be used when making a shared object; recompile with -fPIC
/usr/bin/x86_64-linux-gnu-ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
makefile:22: recipe for target 'libNonsense.so' failed
make: *** [libNonsense.so] Error 1
Apparently, it is compulsory to compile with the -fPIC flag in 64bits platform. If you are making a 32-bits project with linkink with 32-bits library; you don't need -fPIC.
Indeed, without -fPIC, the dynamic linker recalculates adresses for global variables and functions (which are not known in advance in the step of compilation). However, in a 64-bits system, it is not possible to use this technique as it is required to guess in advance the size of adress.
PIC (Position Independent Code), a more sophisticated and complicated process is used. https://eli.thegreenplace.net/2011/11/11/position-independent-code-pic-in-shared-libraries-on-x64 for explanations.
As the error message says, you need to recompile with -fPIC. Your current compiler command does not show the -fPIC option:
g++ -I inc -I /usr/include/mono-2.0 -MMD -MF dep/Socket.d -std=c++17 -O3 -fno-stack-protector -fno-unroll-loops -fomit-frame-pointer -Wno-ignored-optimization-argument -c -o obj/Socket.o src/Socket.cpp
Same for -flto by the way—this flag also has to be specified when compiling in order to be effective.

how to pass -fPIC to GCC on linux

I am trying to compile libedit on linux using GCC 5.3 and am getting a cryptic error message.
/home/mybin/libgcc/x86_64-unknown-linux-gnu/5.3.0/../../../libcurses.a(lib_termcap.o): relocation R_X86_64_32 against `_nc_globals' can not be used when making a shared object; recompile with -fPIC
/home/mybin/lib/gcc/x86_64-unknown-linux-gnu/5.3.0/../../../libcurses.a: could not read symbols: Bad value
To what does the recompile with -fPIC refer, ncurses or libedit? and then how do I pass the -fPIC flag. I have tried adding CFLAGS=-fPIC to the configure of ncurses & libedit but still did not work.
I have found may posts on SO about what -fPIC is, but none on how to set the flag.
thanks Art
Perhaps you ran afoul of the changes outlined in Fedora's Changes/Harden All Packages which use a linker spec that only works if you have compiled using either -fPIC or -fPIE. The linker message is almost useless; only the part about -fPIC has any usefulness.
To address this problem, you can add/modify the compiler flags in several ways. One of the simplest is to set it in the CFLAGS environment variable, e.g.,
export CFLAGS='-O -fPIC'
If you happen to be building ncurses, this means that you would have to also be configuring to build only shared libraries, e.g.,
configure --with-shared --without-normal --without-debug
Of course that all works best if you do not have a previous set of makefiles, etc.
You're looking at the wrong part of the error message. The "relocation R_X86_64_32" means that you're trying to build 32-bit code against a 64-bit library or vice versa. Make sure you have selected the same architecture for both.
-fPIC is used to generate position independent code, it is used to create shared libraries. the make file has a problem, to fix it:
edit the Makefile, line 98 :
.c.o:
${CC} ${CFLAGS} -c $<
after CC add -fpic after CC like this :
.c.o:
${CC} -fpic ${CFLAGS} -c $<
also in line 103:
libedit.so: ${OOBJS}
${CC} --shared -o $# ${OOBJS}
add -fpic after --shared:
libedit.so: ${OOBJS}
${CC} --shared -fpic -o $# ${OOBJS}
if you are wondering what is the difference between -fPIC and -fpic note that they both do the same thing but -fpic is more efficient, check this for more informations What is the difference between `-fpic` and `-fPIC` gcc parameters?.

undefined reference while using shared library

I want to use one program as a shared library for an other program.
I started as follows:
I have a application which I have compiled using:
/usr/bin/g++ -I/usr/include/libxml2 -Xlinker -zmuldefs -fPIC -c a.cpp
/usr/bin/g++ -I/usr/include/libxml2 -Xlinker -zmuldefs -fPIC -c b.cpp
/usr/bin/g++ -I/usr/include/libxml2 -Xlinker -zmuldefs -fPIC -c c.cpp
Then I have created a shared object library from the objects I get from this file using this command:
g++ -fPIC -Xlinker -zmuldefs -shared -o libabc.so a.o b.o c.o
After this I get the libabc.so file which I copy to the
sudo cp libabc.so /usr/local/lib/libabc.so
Now when I compile my orignal application which will use this newly created library libabc.so using this command:
/usr/local/lib/libabd.so: undefined reference to `xmlXPathNewContext'
I get errors for all the functions I used from the included library libxml2 in the first application and the function which has this undefined reference is actually the library I include in the first program I mean I have tested it.
So kindly anyone guide me where I need corrections.
You may have to pass the path also using -I/path/to/library, or alternatively export it to LD_LIBRARY_PATH.
I don't see the command line that you used to link your application against your library, but I suppose that adding -lxml2 to the flags passed to the linker should solve the problem.

Resources