2011年2月26日土曜日

qemuでデバッグするよ〜第1回 〜まずは環境を準備する〜

まったく開発の進まないLua-TRON・・・
なんでなんでしょうか(´・ω・`)ションボリ
きっと動かしてデバッグする環境がないからいけないんだ!!
とか思ったので今日はqemuを使って動作環境を立ち上げてみる。
tachama氏からbeagleboard借りてる状態であることはこの際考えないことにする。

と言っても、この前金の蔵もくもく会の時にmaster_q氏に教えてもらったことの復習。
ホスト環境はMacbook Air。もちろんMacOSXだ。
某探検隊のようにMac使ってるのにMacOSXじゃない人達とは一線を画している(´・ω・`)
いたってノーマルなマカーだ。
マカーがノーマルじゃないなんて批判は受け付けない。

まずはインストール
とりあえず、qemuをインストールする。
ソースはwiki.qemu.orgから取得する。
2011/02/26時点での最新は、0.14.0。
パッチは知らん。
ソースを入手したらおもむろに展開して configure & コンパイル。
おっと、configureするときはtargetの指定を忘れてはいけない。
じゃないとエラい時間をとられることになる。必要なターゲットだけコンパイルすればえ〜んだ。
自分が指定したのは、--target-list=arm-softmmu 。
これだけあったらいいんだぜ、まる。
本当はSDLオプションも付けたかったけど、何故か今回はうまくいかなかったからはずした。
次はmakeして、あとは何も起こらないことを祈るばかりだ。
インストールの項目だけどインストールは必要ない。
arm-softmmuというディレクトリに、qemu-system-arm というのができている。
これがARMエミュレーションをするqemuだどん。
こいつをそのまま叩けばqemuが起動する。

次はデバッグ用の環境準備。
必要なgdbはどこぞからパクってくるヨロシ(´・ω・`)
今回はtoolchain系は全部devkit様から拝借している。Lua-TRON開発環境に認定!!
devkitがあればDSソフトもPSPソフトも作れちゃう!!何度でも美味しい!!
devkitのサイトからリンクが辿れなかったのでsourceforgeから落とす。
とりあえずはdevkitARMがあれば無問題。
だが、片っ端から落とすのがあるべきWEB乞食の姿なので、理想を求めて全部落とす。
devkitのインストールは簡単、落として来たファイルを適当なディレクトリに展開してパスを通せばおしまい。
で、環境ができた。

さてデバッグ確認。
./qemu -S -gdb tcp::12345 -kernel targetimage

とかする。
-S は起動直後にqemuを停止させるオプション。・・・らしい。
-gdb tcb::12345 はgdbとの接続に使用するポートを12345にするというオプション。好きな数字を割り当てればおk。-Sオプションと組み合わせることで、gdbからの接続待ちで停止する。・・・らしい。
-kernel オプションは使用するターゲットバイナリの指定だ。ヘルプを見るとLinuxオプションみたいなこと書いてあるけど気にするな。俺はしない。とりあえずチャレンジすればいいんだ。ここで指定するのはどうやらelf形式のファイルのようだ。・・・ソース斜め読みした感じでは。

で、もう一つコンソールをひらいてこちらではgdbを実行する。
コマンドは以下。

./arm-eabi-gdb targetimage

ちゃんとdevkit様からツールチェインをとって来てパスを通していれば実行できるハズ。
gdbコンソールでは、

(gdb) target remote localhost:12345

ってやるとあ〜ら不思議!!
qemu上で動いているカーネルのデバッグができちゃうじゃ、あ〜りませんかぁ〜、あ〜りませんか!?

できない・・・だと(´・ω・`)
何故落ちるんだ、qemu。

という訳で次回につづく。

――――――――
今日や明日のことでは無く、もっと未来の方へ向かう。そう、明後日の方向へ!!

2011年2月16日水曜日

ARMv7アーキテクチャ リファレンス マニュアル読むよ〜第1回

前に呼んでて途中で投げたので、もう一回最初から読むよ(´・ω・`)
大事なところだけ、ここにメモっておく。
ページ番号は太字。

A2-11:
R0〜R12は自由に使える汎用レジスタ。32bit
R13〜R15は使用目的の決まっているレジスタ。32bit
R13はスタックポインタ用。別名SP。
R14はリンクレジスタ。別名LR。
R15はプログラムカウンタ。別名PC。
R15は、
ARMモードの時は実行している命令のアドレス+8
Thumbモードの時は実行している命令のアドレス+4
を指す。

A2-14:
APSRってレジスタがある。
アプリケーションプログラム ステータスレジスタらしい。
CPSRとは違うものなのか?何が違うんだ???
と思ったら同ページ最後3行に書いてあった。
”ARMv7A/RではAPSRとCPSRは同じレジスタ。でもアクセスできる情報がAPSRの方が少ない”とか。

A2-15:
実行状態レジスタ。
CPUが解釈する命令の種別を設定する。ARM命令、Thumb命令、ThumbEE命令、JAVAバイトコード。
曰く、”ARMv7A/RではCPSRレジスタの一部だぜ!!(キリッ”
ISETSTATE・・・なんなんだぜ
実行状態レジスタの設定のことみたいだけど・・・。

A2-17:
ITSTATE・・・スルー!!!
わからないと思ったところは飛ばしたっていいんだぜ。
逃げてもいいんだ、逃げてもいいんだ、逃げてもいいんだ。

A2-20:
ARMv7のVFP実装はVFPv3。
へー(棒

A2-21:
アドバンストSIMDとVFPは同じレジスタを使用する。
このレジスタは拡張機能レジスタと呼ぶ。
MMXがFPUのレジスタを使うようなもんか(´・ω・`)
ところでアドバンストSIMDって何・・・NEONのこと???

アドバンストSIMDビューでは拡張機能レジスタは、
16個の128bitレジスタまたは32個の64bitレジスタとして扱うことができる。
この2つのモードは同時に扱うことができる。

〜A2-67:
丸っとスルー!!!
だってSIMDとFPUの動作の説明だし。

A2-69:
Ahead-Of-Time(AOT)ってなんじゃらほい。

〜A2-80:
スルー!!!
JazelleとかThumbとかの説明だし。

A2-81:
ARMアーキテクチャでいう例外とは以下のものだ。
・リセット
・割込み
・メモリシステムアボート
・未定義命令
・スーパバイザコール(SVC)
浮動小数点例外とJazelle例外条件は含まれないよ。

A2-82:
Yield命令ってのがあって、マルチプロセッサとかマルチスレッド環境下では有効らしいよ。
今やってること重要じゃないんだよねーというヒンティングをCPUに対して行うものらしい。ふーん(´・ω・`)

第A2章まで超スピードでおしまい。

む〜ん、ARM自体の話があんまりでて来なかった(´・ω・`)

――――――――
今日や明日のことでは無く、もっと未来の方へ向かう。そう、明後日の方向へ!!

2011年2月12日土曜日

ARMとスタックと私

さて、初めての技術的内容の投稿。
今日はとあるおじさんの発言が元で興味が湧いたのでスタック操作命令を生成しない関数を作ってみますた(´・ω・`)

そもそもC言語で関数を生成するとスタック操作命令が入っちまいます。
コール側にも入ります。CPUの呼出し規約によるだろとかいう突っ込みは受付ません。
なんでC言語の関数でスタック操作が入るかというと、

  • 戻りアドレスの格納のため
  • ローカル変数領域確保のため
  • 戻り値の格納のため

なんですが、ARMの場合(というかRISC系)の戻り値はレジスタ渡しなので上2つがスタックを使用する理由になりまふ。
ということは、

  • 呼出し元に戻らない
  • ローカル変数は使用しない
  • 戻り値返さない(上述の通り必須ではない)

という起きて破りな関数ならばスタックを一切消費しない関数が作れそうだ。
という訳でまず以下の関数を作ってみた。

コード1:
void  test(void)
{
    while(1);
}

でコンパイルすると以下のコードが生成された(関係箇所だけ抜粋)


00000000 :
   0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
   4: e28db000 add fp, sp, #0
   8: eafffffe b 8

見事にスタック使ってまふ(´・ω・`)
まさにションボリ。

では次はコードを以下のように変えてみた。

コード2:

void  __attribute__((noreturn)) test(void)

{
        while(1);
}


gcc の拡張で関数属性に noreturn を設定。
さて今度はどんなコードが生成されただろうか。


00000000 :
   0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
   4: e28db000 add fp, sp, #0
   8: eafffffe b 8


か、変わっとらんじゃまいか・・・( ꒪⌓꒪)
とかとかいうところでツィッターでこんなこと書いてたら、master_qからアドバイス。
”最適化しる!!”
神降臨〇(≧∀≦)o そうか、最適化で無駄コードを省いてもらえば・・・
ということで、-02 オプションをつけてコンパイルすると以下のコードになった。


00000000 :
   0: eafffffe b 0

キタ━━━━━━(゚∀゚)━━━━━━!!!!



スタック操作が消えた。最適化レベルを -O1 オプションに変えても同じコードが生成された。
とはいえ、こんな何もしない関数でスタック操作命令が排除されても嬉しくない。
ということで、外部変数の操作をちょこちょこ追加してみる。

コード3:
int  a;
int  b;
int  c;

void  __attribute__((noreturn)) test(void)
{
        a = 0;
        b = 10;
        c = a + b;

        while(1);
}

さて、どんなコードが生成されたかと言うと・・・

(最適化オプションは-01)

00000000 :
   0: e3a02000 mov r2, #0
   4: e59f3018 ldr r3, [pc, #24] ; 24
   8: e5832000 str r2, [r3]
   c: e3a0300a mov r3, #10
  10: e59f2010 ldr r2, [pc, #16] ; 28
  14: e5823000 str r3, [r2]
  18: e59f200c ldr r2, [pc, #12] ; 2c
  1c: e5823000 str r3, [r2]
  20: eafffffe b 20
...

バッチリ!!

外部変数の操作を行っていてもスタック操作命令は生成されない。
ところで、noreturn つけても生成されるコードが変わらんかったということは noreturn 付けなくてもいいんじゃまいか!?

コード4:
int  a;
int  b;
int  c;

void  test(void)
{
        a = 0;
        b = 10;
        c = a + b;

        while(1);
}




で、生成されたコードを見ると

00000000 :
   0: e3a02000 mov r2, #0
   4: e59f3018 ldr r3, [pc, #24] ; 24
   8: e5832000 str r2, [r3]
   c: e3a0300a mov r3, #10
  10: e59f2010 ldr r2, [pc, #16] ; 28
  14: e5823000 str r3, [r2]
  18: e59f200c ldr r2, [pc, #12] ; 2c
  1c: e5823000 str r3, [r2]
  20: eafffffe b 20
...

うむ、やはり noreturn は要らない子だったようだ(´・ω・`)
ところで逆アセンブル結果に含まれてる ... は一体なんなんだぜ!?

という訳でスタックを使用しない関数を生成することはできた。
ソフトウェアではとあるタイミングではスタックを使用することができないので、その部分の関数はこうやって書けばよいと。
とはいえ、これだけだと何もできないので、別の関数を呼ぶことを考えるお(´・ω・`)
手始めに以下のコードなんてどうだろう。

コード5:
void  test2(void);

void  test(void)
{
        asm volatile("b test2\n");
        while(1);
}

void  test2(void)
{
        return;
}

なんかジャンプしてるだけ( ꒪⌓꒪)
さて結果は・・・

00000000 :
   0: eafffffe b 8
   4: eafffffe b 4

00000008 :
   8: e12fff1e bx lr

なるほど、スタック消費されない
今度は下のように外部変数いじるのと関数ジャンプを入れてみる。

コード6:
int  a;
int  b;
int  c;

void  test2(void);

void  test(void)
{
        a = 0;
        b = 10;
        c = a + b;
        asm volatile("b test2\n");
        while(1);
}

void  test2(void)
{
        return;
}

生成されたコードは・・・
00000000 :
   0:   e3a02000        mov     r2, #0
   4:   e59f301c        ldr     r3, [pc, #28]   ; 28
   8:   e5832000        str     r2, [r3]
   c:   e3a0300a        mov     r3, #10
  10:   e59f2014        ldr     r2, [pc, #20]   ; 2c
  14:   e5823000        str     r3, [r2]
  18:   e59f2010        ldr     r2, [pc, #16]   ; 30
  1c:   e5823000        str     r3, [r2]
  20:   eafffffe        b       34
  24:   eafffffe        b       24
        ...

00000034 :
  34:   e12fff1e        bx      lr

いいじゃないか、いいじゃないか。
ということで、スタックを使用しない関数を生成する条件は、以下であると(´・ω・`)
  • 呼出し元に戻らない
  • ローカル変数を使用しない
  • 外部変数は触ってもよい
  • 最適化は -O1 以上
  • noreturn は付けなくてもいい
じゃあなんでこんなことやってるかと言うとスタックが触れないからだ。
そんなら初期化したらええやん(´・ω・`) ということで以下のスタック初期化して他の関数を呼ぶ関数を作ってみた。

コード7:
#define  STACK_ADDR   (0x10000000)

void  test2(void);

void  test(void)
{
        asm volatile("mov sp, %0"::"r"(STACK_ADDR));
        asm volatile("b test2\n");
        while(1);
}

void  test2(void)
{
        return;
}

するとコード生成は
00000000 :
   0:   e3a03201        mov     r3, #268435456  ; 0x10000000
   4:   e1a0d003        mov     sp, r3
   8:   eafffffe        b       10
   c:   eafffffe        b       c

00000010 :
  10:   e12fff1e        bx      lr

いいーーーじゃまいかーーーー!!!

でもどうやってもtestの最初の r3 への代入がとれなかった。効果があるのかどうかわからんが -O6 とかやってもダメだった(´・ω・`)
最初から sp に代入するようなコード生成して欲しいのに。
また誰か神が降臨するのを待つか。
ということで実験終了。

おまけ:
スタックは消費しないんだけど、関数はコールしたいじゃないか!!
あとアセンブラの中に直接呼出し関数名書きたくない!!
ということで以下のマクロを考えた。
きっと世の中には既に存在しているに違いないが・・・(´・ω・`)

#define  CALLFUNC(x) asm volatile("mov lr, pc;b "#x)

void  test2(void);

void  test(void)
{
        asm volatile("mov sp, #0x80000000;");
        CALLFUNC(test2);
        while(1);
}

void  test2(void)
{
        return;
}

生成コード
00000000 :
   0: e3a0d102 mov sp, #-2147483648 ; 0x80000000
   4: e1a0e00f mov lr, pc
   8: eafffffe b 10
   c: eafffffe b c

00000010 :
  10: e12fff1e bx lr

赤字のところがマクロに相当。いい感じじゃないか。
とかとかすると、呼び出された関数test2が lr を使って使って返ってくることもできる(´・ω・`)

・・・ふむ、直値で入れると先の余計なコードが消えてるな。
コレをマクロ化することを考えよう。

てな感じで今日の実験は終了。
おつかれさま(´・ω・`)

――――――――

今日や明日のことでは無く、もっと未来の方へ向かう。そう、明後日の方向へ!!

2011年2月5日土曜日

開発合宿初日

合宿で静岡県伊東は山喜旅館に来てます(´・ω・`)
Luaのビルド中です。
十数秒で終わるはずのビルドがまだ完了できません。
setjmpがないとか言われても・・・それは簡単にダミーでごまかせないざます(´・ω・`)ションボリ

晩ご飯はとっても美味しかったす。
とっても融通利かせてくれてこの旅館サービス最高です。

Hさんから借りたBeagleboardに火を入れようとしたんだけど・・・シリアルケーブル持ってくるの忘れた(´・ω・`)ションボリ
さっきからションボリーヌになってる。

今日の時点でわかっている次回合宿での持ち物:
・ノートPC ・・・ 言わずもがな。これがないと合宿に来る意味なし
・マウス ・・・ やっぱいるよね。
・PSP ・・・ 移動中の電車の中で大活躍
・携帯充電器 ・・・ ないと音信不通になってしまう。
・電源ケーブル ・・・ 今回はmaster_qが持参してくれたので助かったお(´・_・`)
・WiMAX ・・・ いろんなところで速度測定したいです。
・実験対象マシン ・・・ Beagleboard ...
・ビール ・・・ ヤル気のもと。
・着替え ・・・ 明日買いに行きます。

山喜旅館での晩ご飯


――――――――
今日や明日のことでは無く、もっと未来の方へ向かう。そう、明後日の方向へ!!