I'm building Unison (a file synchronization executable) for Android using the Android r10e NDK, but this isn't really an Android question.
Android > 5.0 (SDK 21) requires executables to be position-independent. So I pass -pie to arm-linux-androideabi-gcc while compiling, which works:
% hardening-check ./unison
./unison:
Position Independent Executable: yes
...
This works fine on Android 5.0 devices.
Android > 6.0 (SDK 21) still requires executables to be position-independent, but also requires executables to be built without text relocations. So I pass -fPIC to arm-linux-androideabi-gcc while compiling, and it appears to build a binary without text relocations:
% arm-linux-androideabi-readelf -a ./unison |& grep TEXTREL
(no output is shown)
The problem is, I can only satisfy one requirement at a time. If I use -pie and -fPIC together, the resulting executable is position-independent (yay!), but also has text relocations (boo!):
% hardening-check ./unison
./unison:
Position Independent Executable: yes
...
% arm-linux-androideabi-readelf -a ./unison |& grep TEXTREL
0x00000016 (TEXTREL) 0x0
0x0000001e (FLAGS) TEXTREL BIND_NOW
...and Android 6.0 devices refuse to run it:
% adb push unison /data/local/tmp
% adb shell '/data/local/tmp/unison -version'
WARNING: linker: /data/local/tmp/unison has text relocations. This is wasting memory and prevents security hardening. Please fix.
CANNOT LINK EXECUTABLE: can't protect segments for "/data/local/tmp/unison": Permission denied
What's the special sauce needed to get these flags to work together? Or, alternatively, what am I missing? Are PIC and PIE mutually exclusive?
Thanks!
Edit:
I am manually walking through the same process that the OPAM repo goes through to build Unison for Android. Namely:
Build the ocaml cross compilers.
Pull down the Unison source.
Apply a patch:
--- pty.c~ 2010-04-15 19:29:31.000000000 +0200 +++ pty.c 2013-01-16 19:28:56.258812188 +0100 @@ -10,7 +10,7 @@ extern void uerror (char * cmdname, value arg) Noreturn; // openpty -#if defined(__linux) +#if defined(__linux) && !defined(__ANDROID__) #include <pty.h> #define HAS_OPENPTY 1 #endif --- Makefile.OCaml~ 2013-01-16 19:27:10.686807807 +0100 +++ Makefile.OCaml 2013-01-16 19:29:46.814814286 +0100 @@ -136,7 +136,9 @@ # openpty is in the libutil library ifneq ($(OSARCH),solaris) ifneq ($(OSARCH),osx) - CLIBS+=-cclib -lutil + ifneq ($(OSCOMP),android) + CLIBS+=-cclib -lutil + endif endif endif buildexecutable::
Build with:
% make \ UISTYLE=text \ OCAMLOPT="arm-linux-androideabi-ocamlopt -verbose -ccopt '-fPIC -pie'" \ OSCOMP=android
The above process builds a PIE executable that runs fine on Android 5, but fails on Android 6 because it has text relocations. Removing "-pie" above build a binary without text relocations, but is not a PIE executable so it won't run on Android 5 or 6.