I compiled a simple C program for Android via NDK, and ran that on Android.
C source:
#include <stdio.h>
int
main ()
{
printf ("Hello world!\n");
}
Script for compile C source:
#!/bin/bash
PREFIX="/opt/android-ndk-r7"
CC="$PREFIX/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-arm/bin/arm-linux-androideabi-gcc"
NDK="$PREFIX/platforms/android-14/arch-arm"
CFLAGS="-I$NDK/usr/include"
LDFLAGS="-nostdlib -Wl,-rpath-link=$NDK/usr/lib -L$NDK/usr/lib $NDK/usr/lib/crtbegin_dynamic.o -lc"
$CC -o hello hello.c $CFLAGS $LDFLAGS
What happened when I ran program on terminal on Android:
$ export PATH=/data/local/bin:$PATH
$ hello
Hello world!
[1] + Stopped (signal) hello
$ exit
You have stopped jobs.
[1] Illegal instruction hello
$ exit
When I ran program it worked but then occured "Stopped" and "Illegal instruction".
What should I do for solve this problem?
I'm with #Amigable Clark Kent on this. Think about what you've got there.
You tell the compiler that main() is going to return an int. On running, the loader is preparing to receive the returned value from the function, which is never actually returned. It doesn't matter if it's looking for it in a register or the stack, that place will hold the wrong stuff.
Related
Trying to build libwally-core C library for Android on Windows in Cygwin with supplied autotools scripts:
libwally-core
After running
bash tools/build_android_libraries.sh
or
bash tools/autogen.sh
I get the following error:
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, 'build-aux'.
libtoolize: copying file 'build-aux/ltmain.sh'
libtoolize: error: AC_CONFIG_MACRO_DIRS([build-aux/m4]) conflicts with
ACLOCAL.AMFLAGS=-I build-aux/m4
autoreconf-2.69: libtoolize failed with exit status: 1
I tried the following things to no avail:
Re-saved all scripts with Unix line-endings (LF only)
Commenting out "ACLOCAL_AMFLAGS = -I tools/build-aux/m4" in Makefile.am
The error happens at the following place in libtool's source in libtoolize.in:
macrodir="$ac_macrodir"
test -z "$macrodir" && macrodir="$am_macrodir"
if test -n "$am_macrodir" && test -n "$ac_macrodir"; then
test "$am_macrodir" = "$ac_macrodir" \
|| func_fatal_error "AC_CONFIG_MACRO_DIR([$ac_macrodir]) conflicts with ACLOCAL_AMFLAGS=-I $am_macrodir."
fi
I assume that the above makes sure that AC_CONFIG_MACRO_DIR and value after "-I" in ACLOCAL_AMFLAGS are identical (checked for identical line endings with hex editor too). The values are identical in both configure.ac and Makefile.am. However, even if I comment out setting ACLOCAL_AMFLAGS in Makefile.am, the error persits.
I would like to compile the library and generate libwallycore.so. Any insight would be much appreciated.
The Story - I got a script file on a rooted Android Wear device and I want to run it with my c++ code.
First I tried this int ret = system(/system/bin/sh /full/path/a.sh), it turned out that every time system() return with code 127 - command not exists error.
I found this workaround here: system is returning error 127 when called from c++ in linux and I do as #Nikhilendra said:
int ret = execl("/system/bin/sh","/system/bin/sh","/full/path/a.sh",(char*)NULL)
Now my c++ code crash at this line every time, even without return value, so I cant get any error code on this.
Any help is highly appreciated.
EDIT1:
The script a.sh itself runs correctly.
EDIT2:
My question can be understood as a follow-up of system is returning error 127 when called from c++ in linux
If you want to use one of the exec functions to mimic the system call, you have to fork a new child process first because the current process (image) is replaced by the one given in the exec call. That is, the exec will only return, if it failed.
I can't say, if the fork system call works on Android. But, you can check the exec call with this little example. I actually tested it on a Linux machine. EDIT: You may have to change the path of sh to /system/bin/sh.
The content of a.sh:
#!/bin/sh
echo "Hello World."
The content of the C++ test program (called it exec_test).
extern "C" {
#include <unistd.h>
#include <errno.h>
}
#include <iostream>
int main()
{
execl("/bin/sh","sh","./a.sh",NULL);
// execl only returns if it failed
std::cout << "errno: " << errno << std::endl;
return 0;
}
The output:
$ ./exec_test
Hello World.
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.
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.
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