AVR32 C Project from templateのcrt0.x

AVR32 StudioでAVR32 C Project from templateからStandalone版のアプリケーションを指定すると、アセンブラ・ファイルsrc/SOFTWARE_FRAMEWORK/UTILS/STARTUP_FILES/GCC/crt0.xが作成される。trampoline.xのリセット・ハンドラ_trampoline→program_start→このcrt0.xの_stextへやってくる。
お勉強として、crt0.xを眺めてみる。行番号は私が付加したもので、実際には存在せず、行番号が飛んでいるのは不要と判断して削除したため。

54:   .section  .reset, "ax", @progbits

これ以降の定義はセクション.resetに配置される。allocatableとexecutableのフラグ、contains dataタイプが指定されている。

57:   .global _start
58:   .type _start, @function
59: _start:
60:   // Jump to the C runtime startup routine.
61:   lda.w   pc, _stext
64:   // _stext is placed outside the .reset section so that the program entry point
65:   // can be changed without affecting the C runtime startup.
66:   .section  .text._stext, "ax", @progbits

関数_startが定義され、ほぼtrampoline.xの_trampolineとprogram_startと同様の内容であるから、本当はtrampoline.xは不要と思われる。実際のリセット・ハンドラは_trampolineであり、_startはロード・モジュールに取り込まれていない。これはリンク・オプションに「-Wl,-e,_trampoline」があるためらしい。「らしい」というのは、このオプションの正体がよく判らないから(ドキュメントにも無い)。後で調べてみよう。
個人的には複数ファイルにセクション.resetのグローバル関数を定義することは嫌いだ。どれが本当のリセット・ハンドラか判りづらいからだ。

69:   .global _stext
70:   .type _stext, @function
71: _stext:

続いてリセット・ハンドラからジャンプしてくる関数_stextの定義(関数といっても戻ってくることはないけど)。

73:   lda.w   sp, _estack

スタック・ポインタをシンボル_estack(00008000, 内蔵SRAM末尾+1)の位置に割り付ける。lda.wは仮想オペコードで、リンク時の評価により、異なるオペコードに展開される。セクション_estackがどこで定義されているのか判らない。たぶんリンク・オプションの「-Wl,--gc-sections」辺りが怪しいが、これも宿題。

75:   // Set up EVBA so interrupts can be enabled.
76:   lda.w   r0, _evba
77:   mtsr    AVR32_EVBA, r0

例外ハンドラ・テーブルがシンボル_evbaに(たぶん)あり、このアドレスをレジスタEVBA(Exception Vector Base Address)に設定する。システム・レジスタにアクセスするためmtsr(Move To System Register)命令を使用する。

79:   // Enable the exception processing.
80:   csrf    AVR32_SR_EM_OFFSET

例外ハンドラ・テーブルを設定したので、例外処理を有効化する。

82:   // Load initialized data having a global lifetime from the data LMA.
83:   lda.w   r0, _data
84:   lda.w   r1, _edata
85:   cp      r0, r1
86:   brhs    idata_load_loop_end
87:   lda.w   r2, _data_lma
88: idata_load_loop:
89:   ld.d    r4, r2++
90:   st.d    r0++, r4
91:   cp      r0, r1
92:   brlo    idata_load_loop
93: idata_load_loop_end:

C言語の初期値付きstatic/グローバル変数のような初期値つき変数領域を初期化する。内蔵SRAMの該当領域が_dataから_edata-1に存在する(今回の例では_data(0x00000000)、_edata(0x00000008))。85〜86行目は、もし_data≧edataなら初期値つき変数領域が無いので以後の処理を飛ばす。87〜92行目で、初期データが_data_lma(0x800024d0)に存在するのでr2に入れ、_dataを代入したr0の間でコピーする。コピー終了は_edataを保持するr1を越えるまで。ldとst命令のデータ・サイズが.d=4byte=64bitなので、データ転送にはR4だけでなくR5も使われている。記述としてはこうなるんだろうけど、「R4-R5」みたいに書けないとバグの温床になるから嫌だな。
ところで「LMA」とは何の略だろう?ダンプ・リストでは「VMA」と並んでアドレスを示しているので、「Local Memory Address」らしく、「Virtual Memory Address」とは異なり実アドレスを表しているようだが、それならPMAになりそうだ。Architecture Manualでは「Large Memory」という言葉も出てくるけど...うーん、判らない。

95:   // Clear uninitialized data having a global lifetime in the blank static storage section.
96:   lda.w   r0, __bss_start
97:   lda.w   r1, _end
98:   cp      r0, r1
99:   brhs    udata_clear_loop_end
100:   mov     r2, 0
101:   mov     r3, 0
102: udata_clear_loop:
103:   st.d    r0++, r2
104:   cp      r0, r1
105:   brlo    udata_clear_loop
106: udata_clear_loop_end:

未初期化変数領域を0クリアしている。詳細は、1つ手前の初期化変数領域と似ているので省略。

108: #ifdef CONFIG_FRAME_POINTER
109:   // Safety: Set the default "return" @ to the exit routine address.
110:   lda.w   lr, exit
111: #endif

マクロCONFIG_FRAME_POINTER(デフォルトでは未定義)が定義されているとLRレジスタが初期化される。LRレジスタはreturnするアドレスが格納されているが、コールせず(LRレジスタに戻り先アドレスが格納されない)にリターンすると明後日の方向に飛んでいってしまう。こういう不慮の事故を防ぐ安全策として予めexitへのアドレスを格納している。Fail to safeの考え方だが、exitに飛んだからといって安全か(問題無いか)というのは別の話。

113:   // Start the show.
114:   lda.w   pc, main

最後にユーザ・プログラムのmainに飛んでいく。
あれ?!「_main」じゃない!!
C言語で作成されたシンボルはコンパイルされた時点(アセンブル記述に変換されたとき)で、シンボルの前に「_」が付く。これはUNIX以来の伝統だ。当初アセンブラでプログラムされていたところにUNIXC言語が登場したが、ライブラリ(当然アセンブラで作成)のシンボルと衝突することがしばしばあった(シンボル名の長さが8文字(たぶん)という制限の影響が大きい)。これを自動的に回避する対処方法だった。だからアセンブラからC言語のシンボルを参照するには「_」を付加する必要があるし、C言語側から呼び出すアセンブラのシンボルには予め「_」を付けて定義するだが、AVR32-gccでは不要なのか?
ちなみにコンパイラ内部で利用するシンボルは、先頭に「__」(2文字)を付けるそうな。

このソースは、「C言語スタートアップ・ルーチン」なので、C言語のアプリケーションやライブラリに関する最低限の処理しか実施していない。ハードウェアの初期化など、例外ハンドラ・テーブルとの絡みがあるEVBAとLRレジスタのみ初期化する。
OS上で稼働するアプリケーションなら、main関数は直ちにアプリケーションの機能を実現するところだが、スタンドアローンのmain関数はまずハードウェアの初期化から実施する必要がある。