Home > android > AndroidでNative実行入門

AndroidでNative実行入門

前回のエントリ「Mac OSXのAndroid m5-rc14でNativeファイルがSegmentation faultになる」では、MacでCプログラムをARM用にクロスコンパイルしたネイティブファイルをAndroidで実行して失敗しました。
そのコメントで色々アドバイスを頂き、成功しました。
本エントリではその内容を整理して説明します。
#MichaeLさん、安藤恐竜さん、ありがとうございました。

環境構築
環境

クロスコンパイル環境を構築します。
以下の環境で成功しました。

  • OS: CentOS4.3
  • CPU: Pen4
  • Mem: 2GB

もしくは、

  • 仮想マシン: VMWare Fusion 1.1.1
  • Host: Mac OSX 10.5.2
  • Guest: CentOS5.1 or Ubuntu7
  • CPU: 2GHz Intel Core Duo (iMac)
  • Mem: 2GB

今回使用したクロスコンパイラが32ビット向けなので、いずれのOSも32ビット版(i386)を準備しました。

クロスコンパイラ

クロスコンパイラはDownload the ARM 2007q3 Releaseから、

  • Target Platform: ARM GNU/Linux
  • Host Platform: IA32 GNU/Linux

として、ダウンロードしてきました。

失敗したクロスコンパイラもご紹介

Androidでうまく実行出来なかったクロスコンパイラもご紹介しておきます。
GNU ARM: Mac用のバイナリなども配布してくれています。しかし、Mac版のバイナリではクロスコンパイルできるのですが、Androidで実行できませんでした。(ref. Mac OSXのAndroid m5-rc14でNativeファイルがSegmentation faultになる)

ARM GCC toolchain for Linux and Mac OS X: ここでもMac(Intel)用のバイナリを配布してくれています。上と同じく、クロスコンパイルしたファイルはAndroidで実行できないバイナリでした。

失敗したバイナリファイルはこうなっています。

$ file hello
hello: ELF 32-bit LSB executable, ARM, version 1 (ARM), statically linked, not stripped
ソースコード

前回と同じくHello, world!プログラムをクロスコンパイルしてAndroid上で実行を試みます。

hello.c

#include <stdio.h>
 
int main(int argc, char** argv) {
  printf("Hello, world!\n");
  return 0;
}
Androidでネイティブ実行
クロスコンパイル

さっそく準備したクロスコンパイラでソースコードをコンパイルします。

$ ./arm-none-linux-gnueabi-gcc –version
arm-none-linux-gnueabi-gcc (CodeSourcery Sourcery G++ Lite 2007q3-51) 4.2.1
$ ./arm-none-linux-gnueabi-gcc -o hello-static hello.c -static

staticオプションでライブラリをバイナリに取り込んでいます。
これで、ライブラリに依存しない実行ファイルにできます。

コンパイルしたhello-staticファイルはこうなっています。

$ file hello-static
hello-static: ELF 32-bit LSB executable, ARM, version 1 (SYSV), for GNU/Linux 2.6.14, statically linked, not stripped

ちゃんとstatically linkedされています。

Androidに移動して実行

バイナリファイルをAndroidに移して実行します。

$ adb push hello-static /tmp
$ adb shell
# cd /tmp
# chmod 755 hello-static
# ./hello-static
Hello, world!

うまく行きました!

動的リンクな実行ファイル

上ではstaticオプションによりライブラリをバイナリファイルに取り込んでいました。
そのため、ファイルサイズは大きくなってしまいます。

$ du -h hello-static
564K hello-static

Hello, world!だけで564KBは大きいですね。

次に、Android上で動作する動的リンクなバイナリを生成します。

ソースコード(dynamic link用)

Hello, world!は同じです。

hello.c

#include <stdio.h>
 
int main(int argc, char** argv) {
  printf("Hello, world!\n");
  return 0;
}

hello.c以外にもう1つファイルを準備します。

start.c

#include <stdlib.h>
extern int main(int argc, char** argv);
 
void _start(int argc, char** argv) {
  exit( main(argc, argv) );
}

エントリーポイントとなる_start関数を自前で準備しています。

動的リンクと実行
動的リンクとクロスコンパイル

さっそく、上のソースコードをクロスコンパイルします。
今回はstaticオプションを付けず、動的リンクするバイナリを生成します。

$ ./arm-none-linux-gnueabi-gcc -c hello.c
$ ./arm-none-linux-gnueabi-gcc -c start.c
$./arm-none-linux-gnueabi-ld –entry=_start –dynamic-linker /system/bin/linker -rpath /system/lib -lc -o hello-dynamic hello.o start.o

上の2行はオブジェクトファイルを生成しているだけです。
キモは3行目のコマンドです。下記の3つのオプションを指定します。

  • entry: エントリポイントとなる関数名を指定します。
  • dynamic-linker: ダイナミックリンカの場所を指定します。ここはAndroidのリンカの場所を指定。
  • rpath: ローダがライブラリを検索するパスを指定します。ここはAndroidのライブラリの場所を指定。

ファイル情報を見てみます。

$ file hello-dynamic
hello-dynamic: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped

ちゃんとdynamically linkedとなっています。
これで動的リンクするバイナリを生成することができました。

Androidで動的リンクなバイナリを実行する

さっそく、動的リンクなバイナリをAndroidに移動して、実行してみます。

$ adb push hello-dynamic /tmp
$ adb shell
# adb cd /tmp
# chmod 755 hello-dynamic
# ./hello-dynamic
Hello, world!

ちゃんと実行出来ました!
ちなみに静的リンクなバイナリファイル(hello-static)と動的リンクなバイナリファイル(hello-static)のサイズを比較してみます。

$ du -h hello-*
8.0K hello-dynamic
564K hello-static

ファイルサイズの差は一目瞭然ですね。

おわりに

アドバイスを頂いた、MichaeLさん、安藤恐竜さん、ありがとうございました。とても勉強になりました。

関連サイト

motz diary: AndroidのNative Appに関して一番詳しいそうです。
AndroidでC言語で書いたネイティブアプリを動かしてみる: ScratchBoxというのを利用してクロスコンパイルしているみたいです。こんど試してみよう。

関連のありそうなエントリ

Comments:5

安藤恐竜 08-03-02 (日) 21:45

このエントリはかなりスゴイ。かっこいいです。クラッシュコースをハイウェイに変えるのは難しいんですよ。勉強になりました。

adamrocker 08-03-02 (日) 23:53

ありがとうございます。
失敗例も重要な情報ですよね。同じ失敗を他の人が繰り返さないためにも。
失敗例を晒す事で、沢山のアドバイスも頂けましたし感謝です。

吉田 博 08-04-03 (木) 16:20

ここの資料、大変勉強になりました。
ただ、私はWindows上でコンパイルしているのですが
最後のhello-dynamicで以下のエラーが出てしまいます。

# ./hello-dynamic
./hello-dynamic
ERROR: 592 could not load ‘libc.so.6′
ERROR: failed to link ./hello-dynamic
ERROR: CANNOT LINK EXECUTABLE ‘./hello-dynamic’

何か情報を得られたらと思うのですが、いかがでしょうか?

(ちなみにstaticのほうは実行できましたし、
dynamicのビルドも問題はありませんでした。)

adamrocker 08-04-03 (木) 21:13

>吉田 博さん
コメントありがとうございます。
お役に立てたようで嬉しいです^^
エラー文からするにlibc.so.6が見つかっていないようなので、
libc.so.6というシンボリックリンクを作るとどうでしょう?
こんな感じでしょうか。

$ adb shell
# cd /system/lib
# ln -s libc.so libc.so.6

私もこの作業をやった気もするのですが、try and errorを繰り返していましたので曖昧な記憶です(汗)

吉田 博 08-04-04 (金) 9:15

シンボリックリンクを作成したところ、
hello-dynamicが動きました。
ありがとうございました。

Comment Form
Remember personal info

*
To prove that you're not a bot, enter this code
Anti-Spam Image

Trackbacks:1

Trackback URL for this entry
http://www.adamrocker.com/blog/191/c_native_executable_file_on_android.html/trackback/
Listed below are links to weblogs that reference
AndroidでNative実行入門 from throw Life
trackback from Okiraku Programming 08-06-24 (火) 5:17

[Linux] Android SDKで遊んでみた…

とりあえずダウンロード&起動 Mac OS X 10.5な環境で試してみます。Googleからダウンロードするといきなり動かせます。この簡単さは偉いなあ。 1. ht (more…)

Home > android > AndroidでNative実行入門

Search
Feeds
Meta

Return to page top