How to compile and run a simple C code for Android? - android

Here is the basic C source code :
#include <stdio.h>
int main(void) {
puts("hello world!");
return 0;
}
I am able to compile for Android with NDK toolchain with :
aarch64-linux-android21-clang test.c
It generates an a.out file that I transfer to the Android device with :
adb push a.out /data/local/tmp
adb shell chmod 777 /data/local/tmp/a.out
When I try to run it with:
adb shell /data/local/tmp/a.out
I have the message : "/system/bin/sh: /data/local/tmp/a.out: No such file or directory"
What am I doing wrong?

you can use this nodejs script to automate build and test your c/c++ program for android
let cpp=`
#include<iostream>
#include<string>
using namespace std;
int main(){
cout<<"hellow word"<<endl;
return 0;
}
`
let args=['--target=armv7a-linux-androideabi23']
let cpu="armeabi-v7a"
wfs('test.cpp',cpp)
args.push("test.cpp")
args.push("-static-libstdc++")
//in case you want to build sharedlib uncomment next line
//args.push("-shared")
lg=run(runners.clang,args)
lg=run(runners.adb,'push a.out /data/local/tmp/a.out')
//in case -static-libstdc++ not used uncomment next line;
//copy c++_shared to same dir where to a.out
//run(adb,'push c++_shared.so /data/local/tmp/c++_shared.so')
let shellcmd=[];
shellcmd.push("cd /data/local/tmp")
//in case -static-libstdc++ not used uncomment next line;
// shellcmd.push("export LD_LIBRARY_PATH=.")
shellcmd.push("chmod +x a.out")
shellcmd.push("./a.out")
// a.out excution result
let output=run(runners.adb,`shell "${shellcmd.join("&&")}"`)
lg(output)
//++++++++++utilis++++++++++
function lg(...args){
console.log(...args)
}
function run(cmd,args){
if(args) cmd= cmd+" "+args.join(" ");
return require('child_process').execSync(cmd);
}
function wfs(p,data){
require("fs").writeFileSync(p,data)
}

In my case, I had to use "armv7a-linux-androideabiXX-clang" for compilation and then it is ok. XX must be replaced by the API version.
On my windows system, clang binaries and scripts are in the folder "D:\AndroidSdk\ndk\21.1.6352462\toolchains\llvm\prebuilt\windows-x86_64\bin"
The most recent script that can be used is "armv7a-linux-androideabi29-clang++.cmd" and it is ok for compiling C sourcecodes for running on Samsung A3 phones in my case.
I think this is because this is not a 64-bit kernel and I figured that out after Eugene Sh asked me in comments to this question (if he adds an answer then I'll accept it).

Related

Executing share object file

All discussions are for x86.
If I wrote a simple hello program such as the one below:
#include <stdio.h>
int main(){
printf("Hello\n");
return 0;
}
And compile it on my PC with ubuntu
$gcc -shared -mPIC -o hello_new hello.c
Then it will give me segmentation fault when I try to execute hello_new. Same error when I move this binary to an android phone. (But I can compile it as a binary with statically linked libc and run it on the android phone)
Yes, I want to execute a shared object directly.
The reason is below:
I recently get a linux file compiled by someone else. When I use linux command file and readelf to analyze the file. It says it is a shared object (32-bit, compiled with -m32). But I can execute the shared object like an executable in android on a phone:
$./hello
This really confuses me. This shared object file contains printf function calls, not sure if it is statically link or dynamically linked. But since it can run on Android through ADB, I assume it is statically linked against libc.
What kind of compilation technique can allow one to execute shared object directly?
It happens that I am currently working on this type of thing.
One of the main differences between executables and shared object under linux, is that an executable has an interpreter and a (valid) entry point.
For example, on a minimal program :
$ echo 'int main;' | gcc -xc -
If you look at it's elf program headers:
$ readelf --program-headers a.out
...
INTERP 0x0000000000000200 0x0000000000400200 0x0000000000400200
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
...
The interpreter program is responsible of the execution of the program, to achieve this, it will perform some initializations like loading the needed shared objects. In fact, it is quite analogous to a script shebang, but for elf files.
In this case, /lib64/ld-linux-x86-64.so.2 is the loader for amd64. You can have multiples loaders: e.g., one for 32bits, one for 64.
Now the entry point :
$ readelf --file-header a.out
ELF Header:
...
Entry point address: 0x4003c0
...
$ readelf -a a.out | grep -w _start
57: 00000000004003c0 0 FUNC GLOBAL DEFAULT 13 _start
By default, you can see that _start is defined as the entry point.
So if you consider the following minimal example :
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef INTERPRETER
const char interp[] __attribute__((section(".interp"))) = INTERPRETER;
#endif /* INTERPRETER */
void entry_point(void) {
fprintf(stderr, "hello executable shared object world !\n");
_exit(EXIT_SUCCESS);
}
If you compile it as a "normal" shared object and execute it :
$ gcc libexecutable.c -Wall -Wextra -fPIC -shared -o libexecutable.so
$ ./libexecutable.so
Erreur de segmentation
You can see it segfaults. But now if you define an interpreter (adapt it's path to what readelf --program-headers gave you before) and tell to the linker what is your entry point :
$ gcc libexecutable.c -Wall -Wextra -fPIC -shared -o libexecutable.so -DINTERPRETER=\"/lib64/ld-linux-x86-64.so.2\" -Wl,-e,entry_point
$ ./libexecutable.so hello executable shared object world !
now it works. Please note that the _exit() call is necessary to avoid a segfault at the end of the execution.
But in the end, remember that because you specify a custom entry point, you will bypass libc initialization steps which could be needed or not, depending on your needs.
I think your android and pc boths are x86 or arm at the same time, else executable should not run in both platform. Now to make a shared library executable at the same time you can use -pie command line option of gcc. Details can be found in this answer.

Native libs cross compiled from ubuntu linux targeting arm (android)

I'm experimenting with native libs cross compiled from ubuntu. What I really want is to be able to compile my c++ libraries and use them in a Xamarin.Android app.
First, I have the arm gcc compiler: arm-linux-gnueabi-gcc. I have a simple lib (libmr.so) that has one function void Print(); that prints something to the console. I'm compiling with:
arm-linux-gnueabi-gcc -Wall -shared -o libmr.so mr.c
When inspecting it using file libmr.so everything seems to be good. However when I'm including it with my android app and try to load it, it is as if it doesn't exist. I'm certain it is there, the path is absolutely correct as I tried to load another lib (libmonodroid.so) from the same folder and it worked.
I tried inspecting both libs to find some kind of a difference:
$ objdump -x libmr.so | grep NEEDED
NEEDED libc.so.6
$ objdump -x libmonodroid.so | grep NEEDED
NEEDED libc.so
... (in addition to other libs)
This is the only difference I'm finding between the two. libmonodroid.so loads properly but libmr.so acts as if it doesn't exist. (I'm using dlopen to load a lib)
EDIT:
I built an executable using the same toolchain, gave me a clue:
Static linking with libc: arm-linux-gnueabi-gcc -Wall -o hi source.c -static. Pushed hi to my android devices and executed it with adb. Result: SUCCESS!
Dynamic linking with libc: arm-linux-gnueabi-gcc -Wall -o hi source.c. Result: it's not even there! Meaning ./hi gives /system/bin/sh: ./hi: not found although it's absolutely there.
So, looks like libc is really the culprit? Maybe I need to link dynamically with not libc.so.6 but with libc.so just like libmonodroid.so is doing?
Check this out for anyone having the same problem. Download the ndk, there's a standalone toolchain for building native libs that run on android that you can extract (you won't need the whole ndk).
I was able to run a basic app on ubuntu 15.04 with this Makefile in the same dir as my hi.c:
$ cat hi.c # create hi.c with favorite editor
#include <stdio.h>
int main(int argc, char** argv) {
int uid = getuid();
int eid = geteuid();
printf("Hello world\n");
printf("You are uid: %d and eid; %d", uid, eid);
return 0;
}
$ cat Makefile # create two line Makefile
CC=arm-linux-gnueabi-gcc
LDFLAGS=-static
$ make hi # build arm based hi executable file
arm-linux-gnueabi-gcc -static hi.c -o hi
$ file hi # check file type
hi: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=17b65e60cdd32449ac237bfd1b8238bfa1d416a0, not stripped
$ adb push hi /data/local/tmp # copy to droid fon
4403 KB/s (593252 bytes in 0.131s)
$ adb shell /data/local/tmp/hi # run hi executable
adb shell /data/local/tmp/hi
Hello world
You are uid: 2000 and eid; 2000
$ uname -a
Linux lenny 3.19.0-28-generic #30-Ubuntu SMP Mon Aug 31 15:52:51 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
Note that I do not have any NDK installed.

Can Gcc build a executable program?

All, Forgive me I am familiar with the C program for the Android/Linux platform. Now I am trying to use the Sourcery G++ Lite Edition
for ARM to build my sample C program and deploy it to the Linux of the Android platform.
Below is the instructions what I follow.
So far it works fine. But I have something I didn't understand well. please review it . thanks.
The Source code is a hello world program.
#include <stdio.h>
int main(int argc,char * argv[])
{
printf("Hello, Android!\n");
return 0;
}
In the development machine command console. run the following commands line.
arm-none-linux-gnueabi-gcc hello.c -static -o hellostatic
adb push hellostatic /data/test
adb shell
cd /data/test
.hellostatic
Hello, Android!
So here is my question.
Can gcc build a executable file from a c source code file? Seems It doesn't need link tool. Is it right? thanks.
Can gcc build a executable file from a c source code file?
yes, of course.
Seems It doesn't need link tool?
no, I extract the following sentences from gcc manual,
GCC is capable of preprocessing and compiling several
files either into several assembler input files, or into one assembler input file; then each
assembler input file produces an object file, and linking combines all the object files (those
newly compiled, and those specified as input) into an executable file.
At default gcc will do complie and link operation, unless you type particular options such like:
gcc -c file.c
this will just compile file.c to file.o
or:
gcc -o file file.c
this will complie file.c to file.o and also link it to make a executable file finally.
Although yanchong had already gave the nice answer , I also found a good read from here. I think it will help to understand the concepts of Compile, Link and Build. Thanks.

How to compile C into an executable binary file and run it in Android from Android Shell?

I have a Device on which I installed Android Gingerbread 2.3.4
Here i want to run C executable file on android device
I am able to run android NDK application on this Device and it runs perfect.
But I want to run only one hello.c executable file on the Device.
/* #includes #defines ... */
int main(){
// Do something when this is executed
return 0;
}
Is there any way to compile this file with Android NDK tool chain so I can run this file's executable?
I found one thing here but this is not working for me. I am using Android NDK, Revision 7b for Linux.
There is no directory structure like this.
First, let me say that my answer is dependent on your using NDK r7b (it'll work for r7c as well) on Linux (change paths appropriately for other systems).
Edit: Last tested with NDK r8e on Linux and Nexus 4 with adb from SDK Platform-Tools Rev 18 on Windows 7 (latest as of 2013-07-25) without root access.
Yet Another Edit: Please read this question for altering my instruction for native binaries that need to run on Android 5.0(Lollypop) and later.
Go to $NDK_ROOT (The topmost folder of NDK zip when unzipped).
Copy $NDK_ROOT/samples/hello-jni directory as $NDK_ROOT/sources/hello-world.
Go to $NDK_ROOT/sources/hello-world.
Edit AndroidManifest.xml to give the application an appropriate name (This is optional).
Go to $NDK_ROOT/sources/hello-world/jni. This is where the source code is.
Edit hello-jni.c, remove all the code, and put in your hello world code. Mine is:#include
int main( int argc, char* argv[])
{
printf("Hello, World!");
return 0;
}
Edit Android.mk and change the line include $(BUILD_SHARED_LIBRARY) to include $(BUILD_EXECUTABLE). You can also change the LOCAL_MODULE line to the name you want for your executable(default is hello-jni)
Go back to $NDK_ROOT/sources/hello-world
Run ../../ndk-build to create the executable.
Copy it from $NDK_ROOT/sources/hello-jni/libs/armeabi/hello-jni to /data/local/tmp on the Android device and change it's permissions to 755 (rwxr-xr-x). If you changed the LOCAL_MODULE line in $NDK_ROOT/sources/hello-world/jni/Android.mk, the executable name will be the new value of LOCAL_MODULE instead of hello-jni. (All this is done via adb from the Android SDK.)
Execute the binary with full path as /data/local/tmp/hello-jni, or whatever you named it to.
And you're done( and free to start on the documentation in $NDK_ROOT/docs to get a better idea of what to do).
The best/easiest place to put a executable is /data/local. You'll also need to chmod the binary as executable. Often you'll also need to do this in two steps to get the binary from /sdcard/ to /data/local:
$ adb push mybin /sdcard/
$ adb shell
$ cp /sdcard/mybin /data/local/mybin
$ cd /data/local
$ chmod 751 mybin
Caveats:
Not all systems have cp. You can use cat if this is the case:
$ cat /sdcard/mybin > /data/local/mybin
Some systems don't allow write in /data/local for the "shell" user. Try /data/local/tmp
the "/sdcard" location is not executable, meaning that any file there is not executable at all.
the only way to "adb push" executable would be to put them in "/data/local", which should be writable for adb, and allow execution for anyone.
I recently had the same problem on a new nexus-5. I'd like to add that /data/local was not writable by the user ("shell", uid 2000) I got with adb shell. But putting the executable in the subdirectory /data/local/tmp/ worked fine.
In a nutshell,
First, to cross-compile your C code from your host machine, use NDK toolchain with sysroot option and position independent option -fPIE -pie.
$NDKROOT/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-gcc \
--sysroot=$NDKROOT/platforms/android-22/arch-arm64 -fPIE -pie main.c -o main
the arch part arrch64 or arch-arm64, the toolchain version part 4.9, platform version part android-22, and the binary format for your host machine darwin-x86_64 may vary by your environment.
Second, push your binary under /data/local/tmp and execute it from adb shell.

Using Google Breakpad for Android NDK?

Is anyone using Google Breakpad for Android native code (NDK) ?
If so, could you elaborate on how to get it up and running (the client side that is).
The docs are very limited and don't mention Android at all. The build system contains android information though which make me think it shouldn't be a problem.
Sorry about that, I did the initial port but I didn't really document anything. However, one of the Chrome engineers did some work on the port and wrote a really nice README:
https://chromium.googlesource.com/breakpad/breakpad/+/master/README.ANDROID
There's also an NDK-compatible Android.mk file in there now, so if you're using the standard NDK build system it should be simple to incorporate Breakpad.
I also found a good example project for that.
As it is in the project you can set up Google Breakpad like:
extern "C" {
void Java_com_pluusystem_breakpadjavacall_MainActivity_initNative(JNIEnv* env, jobject obj, jstring filepath)
{
const char *path = env->GetStringUTFChars(filepath, 0);
google_breakpad::MinidumpDescriptor descriptor(path);
exceptionHandler = new google_breakpad::ExceptionHandler(descriptor, NULL, DumpCallback, NULL, true, -1);
}
}
in the cpp side and like:
// Save Dump Path
initNative(getExternalCacheDir().getAbsolutePath());
in the java side.
After that implementing the bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) function you will be able to do something before the app crashes.
I have experienced and also found this issue which confirms me, that in this function you can't do java callbacks under ART just under DVM (before android 5 - Lollipop).
My example repo for Flutter Android/iOS: https://github.com/Sunbreak/flutter-breakpad.trial
Android
Build libbreakpad_client.a on Linux (e.g. https://multipass.run/)
$NDK is local path of your Android NDK directory
$CLI_BREAKPAD is local clone of https://github.com/Sunbreak/cli-breakpad.trial
cd $BREAKPAD/src/android
cp -r google_breakpad jni
$NDK/ndk-build
Install libbreakpad_client.a of all architectures
mkdir -p ./android/app/src/main/cmakeLibs
cp -r $BREAKPAD/src/android/obj/local/* ./android/app/src/main/cmakeLibs/
run on macOS/Linux
# Device/emulator connected
$ android_abi=`adb shell getprop ro.product.cpu.abi`
$ flutter run
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
I/flutter_breakpad(31631): JNI_OnLoad
D/flutter_breakpad(31631): Dump path: /data/data/com.example.flutter_breakpad/files/f5258c0e-eff3-433a-7ea47880-c756fc17.dmp
$ adb shell "run-as com.example.flutter_breakpad sh -c 'cat /data/data/com.example.flutter_breakpad/files/f5258c0e-eff3-433a-7ea47880-c756fc17.dmp'" >| libflutter-breakpad.so.dmp
run on Linux (e.g. https://multipass.run/)
$ $CLI_BREAKPAD/breakpad/linux/$(arch)/dump_syms build/app/intermediates/cmake/debug/obj/${android_abi}/libflutter-breakpad.so > libflutter-breakpad.so.sym
$ uuid=`awk 'FNR==1{print \$4}' libflutter-breakpad.so.sym`
$ mkdir -p symbols/libflutter-breakpad.so/$uuid/
$ mv ./libflutter-breakpad.so.sym symbols/libflutter-breakpad.so/$uuid/
$ $CLI_BREAKPAD/breakpad/linux/$(arch)/minidump_stackwalk libflutter-breakpad.so.dmp symbols/ > libflutter-breakpad.so.log

Categories

Resources