Want to compile native Android binary I can run in terminal on the phone
Asked Answered
E

5

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.

Exhibitive answered 29/5, 2012 at 11:37 Comment(4)
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.Mockingbird
Possible duplicate of How can i run C binary (executable file) in Android from Android ShellDacia
How to build an executable for Android shellWoodrum
See the official guide(s), most of the answers here are outdated. For the easiest method (one line compile, no build system), see this.Segregation
B
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
Barragan answered 9/6, 2012 at 23:16 Comment(11)
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!Thaine
$(NDK_ROOT)/docs/ANDROID-MK.html describes what all the macros are.Barragan
there is an extra endifMlawsky
@Barragan - 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?Peaceful
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.Barragan
@myCodeHurts you should not put it on the sdcard as it is not permitted to execute anything from thereMccrary
@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 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.Geddes
@Geddes 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.Barragan
@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.Geddes
@Geddes 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.Barragan
@SonicBison, it actually turned out to be an issue with a call to remove rather than unlink on initialization.Geddes
D
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
Demetricedemetris answered 28/5, 2013 at 5:36 Comment(2)
...are you executing an object file there? Without linking it? Does that really work?Clamshell
Yeah it looks like it. I most likely need to remove the -c. I wrote this a while ago.Demetricedemetris
S
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.

Slavey answered 30/5, 2012 at 13:26 Comment(0)
P
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.

Panocha answered 20/5, 2022 at 14:12 Comment(0)
W
-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.

Winder answered 29/5, 2012 at 12:7 Comment(2)
Why use Crystax in this case instead of official NDK?Lethargy
No special reason, sometimes it helps to try different things when experimenting and learning. That's why I just made it a comment.Winder

© 2022 - 2024 — McMap. All rights reserved.