39

I've been trying for a couple days to compile a native ARM Android binary that will execute on my phone using a terminal application. I want to generate the same type of binary as the standard Posix binaries installed on the phone like ls, mkdir etc. I've downloaded the Android NDK under Mac OS X and have been able to compile simple ELF binaries without errors. However, when I transfer them to the phone, they always segfault. That is, they segfault when compiled with -static in GCC. If I don't use -static, they complain about not being linked, etc. Put simply, they don't work.

My hypothesis is that they are not linking to the Android standard C library properly. Even though I am linking my binaries with the libc provided by the NDK, they still don't work. I read that Android uses the Bionic C library, and tried to download source for it but I'm not sure how to build a library from it (it's all ARM assembly, it seems).

Is it true that the Android C library on the phone is different from the one provided with the Android NDK? Will the one included with the NDK not allow me to compile native binaries I can execute through a terminal? Any guidance here is greatly appreciated!

Update:

I finally got this to work using GCC 4.7.0 on Mac OS X. I downloaded the Bionic headers and then compiled a dynamically linked binary using the C library that comes with the Android NDK. I was able to get a test app to work on the phone using the phone's C lib (the binary was 33K). I also tried to statically link against the NDK's C library, and that also worked.

In order to get this all working I had to pass -nostdlib to GCC and then manually add crtbegin_dynamic.o and crtend_android.o to GCC's command line. It works something like this:

$CC \
$NDK_PATH/usr/lib/crtbegin_dynamic.o \
hello.c -o hello \
$CFLAGS \
$NDK_PATH/usr/lib/crtend_android.o

For static binaries, use "crtbegin_static.o." This is explained in the crtbegin_dynamic.S/crtbegin_static.S source.

For this experiment, I only used plain 'ol GCC 4.7.0 and Binutils 2.22. I also compiled GCC with newlib, but I am not actually linking my ARM binaries with newlib at all. I am forcing GCC/ld to link directly to the libc provided with the Android NDK, or in the case of dynamic binaries, to the libc on the phone.

Synthetix
  • 2,035
  • 3
  • 24
  • 30
  • FYI, if you set up a build as if you were making a jni library (see the examples in the NDK distribution) and change BUILD_SHARED_LIBRARY in the Android.mk to BUILD_EXECUTABLE you will get an executable, though this is an unofficial (might go away, etc) feature of the ndk build system. – Chris Stratton May 30 '12 at 17:40
  • Possible duplicate of [How can i run C binary (executable file) in Android from Android Shell](http://stackoverflow.com/questions/9868309/how-can-i-run-c-binary-executable-file-in-android-from-android-shell) – Ciro Santilli OurBigBook.com Jun 23 '16 at 17:32
  • [How to build an executable for Android shell](https://stackoverflow.com/q/35231168/3290339) – Onik Oct 31 '18 at 22:02
  • See the [official guide(s)](https://developer.android.com/ndk/guides/build), most of the answers here are outdated. For the easiest method (one line compile, no build system), see [this](https://developer.android.com/ndk/guides/other_build_systems). – user_ Jun 09 '23 at 12:43

5 Answers5

21

Just use the android-ndk. And build a Android.mk like so. include $(BUILD_EXECUTABLE) is what tells it build a executable instead of a JNI .lib

Android.mk

ifneq ($(TARGET_SIMULATOR),true)

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_CFLAGS += -Wall


LOCAL_LDLIBS := -L$(LOCAL_PATH)/lib -llog -g

LOCAL_C_INCLUDES := bionic
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include

LOCAL_SRC_FILES:= main.cpp

LOCAL_MODULE := mycmd

include $(BUILD_EXECUTABLE)

endif  # TARGET_SIMULATOR != true
SonicBison
  • 790
  • 7
  • 21
  • This was the solution for me. I've benn tinkering with agcc without success. This seems to take advantage of the android build system... Is there some explanation on how it works somewhere? Thanks! – Diego Medaglia Apr 01 '13 at 22:41
  • $(NDK_ROOT)/docs/ANDROID-MK.html describes what all the macros are. – SonicBison Apr 04 '13 at 00:54
  • there is an extra `endif` – dashesy Sep 24 '13 at 20:58
  • @SonicBison - So I did succeed in compiling the binary. Now Is there any specific place where we "Should" put the binary? My device is rooted. If I perform a CHMOD to 777, will it behave like SU and get system app kind of access like INEJCT_EVENTS permission. Basically I want to call injectEvents at the end of the day? – TorukMakto Jan 31 '14 at 23:05
  • I don't know anything about INJECT_EVENTS, but a quick googling says the app needs to be signed by the system(platform) key. But otherwise w/ root you can put the binary anywhere. – SonicBison Feb 04 '14 at 01:18
  • 1
    @myCodeHurts you should not put it on the sdcard as it is not permitted to execute anything from there – JoachimR May 09 '14 at 20:04
  • @SonicBison, is the notion of an application permissions file (i.e. a *manifest*) still required for standalone programs like these? I've developed a [simple unix socket](http://stackoverflow.com/questions/32100814/unable-to-do-af-unix-socket-ipc-in-android-using-ndk-operation-not-permitted) native program that is having what appear to be permission-related issues. I was thinking perhaps I was missing something during the compilation phase related to this. – sherrellbc Aug 20 '15 at 17:02
  • @sherrellbc No. It will have conform to regular file system permissions , i.e. make sure the directory is readable/writeable. If it is a non-rooted device then this is only in a handfull of places. – SonicBison Aug 20 '15 at 18:33
  • @SonicBison, the phone is rooted. The directory where the socket-files are placed has permissions `drwxrwx---` and the file I am attempting to connect to has permissions `srwx---rw-`. I am running both executables as root, so should this be an issue? Without root execution of the executables I get permissions errors when trying to write to the directory, as expected. However, as the link to my question above shows, I am getting `Operation not permitted` errors when run as root for both `connect` and `send`/`sendto` syscalls, while `bind` works as expected. – sherrellbc Aug 21 '15 at 14:18
  • @sherrellbc for your case it sounds like it should work. i my case we have it set 0777 because we have different .apks connect to a daemon. – SonicBison Aug 22 '15 at 18:11
  • @SonicBison, it actually turned out to be an issue with a call to `remove` rather than `unlink` on initialization. – sherrellbc Aug 24 '15 at 02:22
16

First, make sure you have the NDK:

http://developer.android.com/tools/sdk/ndk/index.html

Here is the easiest way to compile a C binary for your phone:

http://developer.android.com/tools/sdk/ndk/index.html

http://www.kandroid.org/ndk/docs/STANDALONE-TOOLCHAIN.html

Usually $NDK(may be different) =

Linux:

/home/<user>/android-ndk

Mac OS X:

/Users/<user>/android-ndk

In Terminal:

# create tool-chain - one line
# New method in ndk 12.
$NDK/build/tools/make_standalone_toolchain.py --arch arm --install-dir=/tmp/my-android-toolchain
# Old method.
#$NDK/build/tools/make-standalone-toolchain.sh --platform=android-3 --install-dir=/tmp/my-android-toolchain

# add to terminal PATH variable
export PATH=/tmp/my-android-toolchain/bin:$PATH

# make alias CC be the new gcc binary
export CC=arm-linux-androideabi-gcc

# compile your C code(I tried hello world)
$CC -o foo.o -c foo.c

# push binary to phone
adb push foo.o /data/local/tmp

# execute binary
adb /data/local/tmp/foo.o
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
3

Using CMake with the Android NDK is a nice way to compile Android console applications.

Download CMake and android-cmake (set it up like this). If your program is called main.c, then write the following in file CMakeLists.txt:

project(test)
cmake_minimum_required(VERSION 2.8)
add_executable(test ./main.c)

and run cmake -DCMAKE_TOOLCHAIN_FILE=$ANDTOOLCHAIN .

You will then have a Makefile for your program, you can run make to have your test executable.

gfour
  • 959
  • 6
  • 9
0

In CMake, you can cross build using toolchain files.

From google developers:

cmake \
    -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
    -DANDROID_ABI=$ABI \
    -DANDROID_PLATFORM=android-$MINSDKVERSION \
    $OTHER_ARGS

CMake has its own built-in NDK support. Before CMake 3.21, this workflow is not supported by Android and is often broken with new NDK releases. Starting from CMake 3.21, the implementations are merged.

Starting from cmake 3.21 you can:

mkdir build
cd build
cmake ..
  -DCMAKE_SYSTEM_NAME=Android
  -DCMAKE_SYSTEM_VERSION=23 # API level. optional, recommanded
  -DCMAKE_ANDROID_NDK=path/to/ndk
  -DCMAKE_ANDROID_ARCH=arm # optional, recommanded
  -DCMAKE_ANDROID_ARCH_ABI=armeabi # optional, recommanded

Note: in the command above, line endings (<line feed>) are not escaped, please don't copy-paste this command directly in your shell

See Cross Compiling for Android with the NDK for more information about variables, possible values, and determenation algorithms.

Ahmed Shaqanbi
  • 525
  • 5
  • 15
-1

Try if if the agcc wrapper can help you as referenced in the Android-tricks blog. According to the blog post you want to use the bionic library, but the one already installed on the phone, not some separately compiled version.

Prof. Falken
  • 24,226
  • 19
  • 100
  • 173