ARMにも興味がある今日この頃、ARMで学ぶ アセンブリ言語入門
という本を買ってみました。
特に読みたかったのはチャプター7の例外と割り込みの所ですねー。初めて読む486を読んだり、自作OS作成経験ある人には面白い章なんじゃないかと思います。
さて。早速遊んで見ようと思って気づいたことなどをめも。
まずは、必要な物としてエミュレータ(うちは遊べるような実機ないですし)、クロスコンパイラですね。
コンパイラはgcc-arm-linux-gnuパッケージを入れます。yumで入れれば依存関係でbinutils-arm-linux-gnuパッケージも入るのでクロス開発環境としてはこれでOKです。あとはqemu-system-armパッケージを入れましょう。
これで環境はd( ^ω゜ )バッチリ!!と思ったら罠があります。
[masami@saga:~/codes/mikoto]$ yum info gcc-arm-linux-gnu Loaded plugins: langpacks, refresh-packagekit Installed Packages Name : gcc-arm-linux-gnu Arch : x86_64 Version : 4.7.2 Release : 2.aa.20121114svn.fc19.1 Size : 28 M Repo : installed From repo : fedora Summary : Cross-build binary utilities for arm-linux-gnu URL : http://gcc.gnu.org License : GPLv3+ and GPLv3+ with exceptions and GPLv2+ with exceptions and LGPLv2+ and BSD Description : Cross-build GNU C compiler. : : Only building kernels is currently supported. Support for cross-building : user space programs is not currently provided as that would massively multiply : the number of packages.
Descriptionを読むとgccのクロスコンパイラパッケージはカーネルのビルドしかまだサポートしていないんですね。なので↓のコードもarm用に作ることができません。
#include <stdio.h> int main(int argc, char **argv) { printf("hello, world!\n"); return 0; }
すくなくとも2013/6/30時点でFedoraをホストにしてアプリをコンパイルしようと思ったら自前でツールチェイン等構築するか、エミュレータのarm環境が必要になります。
しかし、アプリはクロスビルドできなくてもカーネルはOKなので、一応遊べます。
俺のなかのマリー・ナントカネットさんが「アプリをクロスコンパイルできないならカーネルを書けば良いじゃない」と言っていましたw
ということで、単純なハローワールドを書いてみました。
書いたのは以下の4個です。
「ARMで学ぶ アセンブリ言語入門」の後半でirqやソフトウェア割り込みの扱いが載っていてそこで使用しているスクリプトを参考にしています。
では、まずはリンカースクリプトから。
ENTRY(mikoto_kernel_start) SECTIONS { . = 0x10000; .text : { *(.entry); *(.text, rodata); } .data : { *(.data); } .bss : { *(.bss); } .stack : { . = . + 0x1000; . = ALIGN(4); stack_top = .; . = . + 0x1000; . = ALIGN(4); irq_stack_top = .; } }
bootで最初に呼ばれるのがmikoto_kernel_start、開始アドレスは0x10000で、スタックは0x1000からと言う感じです。
今回はirqは使って無いけど、一応記述は入れてあります。
次にboot時に呼ばれるアセンブラコード。
.text .code 32 .globl mikoto_kernel_start mikoto_kernel_start: ldr sp, =stack_top bl kernel_main
こちらはものすごく単純にして、スタックを設定したらc関数のkernel_main()を呼ぶだけです。
出力はシリアルポート(UART)です。
cのコードはこちら。
#define UART0 ((volatile unsigned int *) 0x101f1000) #define UARTFR 0x06 #define UARTFR_TXFF 0x20 void puts(const char *s) { while (*s) { while (*(UART0 + UARTFR) & UARTFR_TXFF) ; *UART0 = *s; s++; } } void kernel_main(void) { puts("hello, world!"); while (1); }
最後にMakefileはこちら。
CC = arm-linux-gnu-gcc CFLAGS= -mcpu=arm926ej-s -marm -nostdlib --no-builtin -Wall LD = arm-linux-gnu-ld LDFLAGS = -T mikoto_kernel.ld kernel = mikoto_kernel.img objs = kernel_main.o \ head.o all: $(objs) $(LD) $(LDFLAGS) $(objs) -o $(kernel) .c.o: $(CC) -c $(CFLAGS) $< -c .S.o: $(CC) $(CFLAGS) $< -c clean: -rm *.o *~ test: qemu-system-arm -M versatilepb -nographic -kernel $(kernel) .PHONY: clean all
標準ライブラリは使わないので-nostdlibを付けるのと、gccがビルトインのputsが使おうとするのを防ぐため--no-builtinを付けてます。
そして、qemuで実行する場合はこんな感じのオプションで実行するとちゃんと動きます。
[masami@saga:~/codes/mikoto]$ qemu-system-arm -M versatilepb -nographic -kernel mikoto_kernel.img pulseaudio: set_sink_input_volume() failed pulseaudio: Reason: Invalid argument pulseaudio: set_sink_input_mute() failed pulseaudio: Reason: Invalid argument hello, world!
こんな感じでFedora 19(x86_64)をホストにしてarmバイナリのコンパイル・実行ができました( ´∀`)bグッ!
FedoraのARMプロジェクトではVersatile Expressのイメージを配布しているのでこれで遊ぶこともできます。このイメージのディストリビューションはFedora18となっています。
イメージの取得、動かし方はFedoraProjectのWikiに書かれています。XFCEも動くようなのでGUIありで動かしてみたのが↓の写真です。