.bss.sysmmr と .bss.coremmr

先日のやりとりの結果、Mayaさんが遭遇していた「bfin-elf-gccで作ったLDRファイルがBlackfinでロードしない」と言う問題は、Makefileの中の次のコマンドの副作用によるものでした。

$(OBJCOPY) -R .bss.sysmmr -R .bss.coremmr $(OBJFILE)

このコマンドの起源はなかなかに複雑です。

事の発端

もともとの動機は、「gdbでシステム・レジスタデバッグしたい」というものでした。VisualDSP++はフリーで使い続けることができず、かつ、Windowsでしか動作しないため、私の開発環境であるLinuxでは不便です。一方で、bfin-elf-gdbは当然のようにBlackfinのレジスタを解しないため、デバッグが不便でした。
そこで、.bss.sysmmr .bss.coremmrというセクションを、システム・レジスタ、コア・レジスタと同じアドレスに被せ、中身を初期化しない変数をシステム/コア・レジスタとして宣言することでgdbにシステム・レジスタを変数と思い込ませる方法です。
ところが、これは思いがけない問題を呼び起こしました。ELFはセクションの属性としてNOBITSを指示すると、その領域を初期化しないことになっています。レジスタ領域に変な値を書き込むと暴走しますから初期化はしたくありません。その点、gdbはNOBITSセクションを初期化せずに放って置いてくれます。ところが、ubootはこのセクションを0フィルします。ELF的にはおかしいのですが、ubootのコミュニティはかなり強行です*1

そこで、渋々上のコマンドをMakefileに差し込んだのです。MakefileをいじるとTOPPERS/JSPの公式リリースから離れていくので嫌だったのですが、背に腹は代えられません。
ところが、今度は bfin-elf-ldrです。LDFファイルは最後のセクションに"BFLAG_FINISH"というフラグを置くことで、Blackfinのブートローダーに「ロード後、実行せよ」と指示します。ところが、上のコマンドを入れたばっかりにELFの最後のセクションが削除されてしまいました。そのため、bfin-elf-ldrはBFLAG_FINISHを生成せず、ローダーは正常にブートしませんでした。
まったく、踏んだり蹴ったりです。いや、酷い目に遭ったのはMayaさんですが。

さて、どうする

今後の方針ですが、いくつか考えられます。

  1. MMRの表示をすっぱりあきらめる
  2. MMRのシンボルを別ファイルにする
  3. Makefileをかき分ける
  4. MMRに新しいセクションを加える

最後の方法は、先ほど実験して効果を確かめました。要するに .bss.coremmr が最後のセクションであることが原因なわけで、メモリ最上位にダミーの「最後のセクション」を置く方法です。これがちゃんとBFLAG_FINISHをつくってくれるのですが…なんかダメな気がします。結局ubootでこけそうですよね。
そういうわけで、2,3あたりが合理的じゃないかと思います。2の方法は、レジスタアドレス絡みのトリックを全部外に出して独立したアプリケーションとしてビルドし、必要に応じてgdbのadd_fileコマンドでシンボルを追加する方法です。ubootの問題も回避できますし、これが一番よさそうです。

*1:私はこれでubootへの印象をだいぶ悪くした