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
#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.