初期化データの配置を間違えることがある
Ubunt 9.04, Sourcery G++ lite 2009Q1環境で上記sample1改造プログラムによる現象の再現を確認しました。
arm-none-eabi-readelf -a jsp の結果を見ると、.ARM.exidxという見慣れない出力セクション名があり、どうもそれが.dataセクションの配置を引きずっているのではないかと思える節があります(根拠は薄い)。.ARM.exidxはC++例外処理用のindexですが、例外は使っておらず、なぜこのセクションが現れたかは、不明です。もう少し追求が必要です。
ねむいさんのブログを参考にして、lpc2388.ld ファイルに以下の一節を追加してみました。手元では問題が消えたようです。
__exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > MEM_FLASH
.rodata 出力セクションの宣言の直後に挿入するのが適切と思われます。修正前は
_etext = . ; PROVIDE (etext = .) ; .rodata : { *(.rodata) *(.rodata.str1.4) } > MEM_FLASH
となっているのを、次のように修正します。
_etext = . ; PROVIDE (etext = .) ; .rodata : { *(.rodata) *(.rodata.str1.4) } > MEM_FLASH __exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > MEM_FLASH
確認をお願いします。
Ubuntu 9.10, Sourcery G++ lite 2009Q3環境で、上記のリンカスクリプト変更により問題が解決されることを確認しました。
プログラムの内容によっては、リンク時に初期化データがフラッシュROM(MEM_FLASH)領域ではなく、FIO RAM(MEM_FIO)領域にとられてしまう。その結果、データが正しく初期化できない。
具体的な再現手順を、sample1.c を改造する場合を例に示す。
1. sample1.c の下記の箇所を追加する。
2. make 後、idata_start, idata_endのシンボルの値を確認する。次のようにMEM_FIOの領域に配置されていることが確認できる。
3. 追加した除算の行を削除すれば、同シンボルはMEM_FLASH領域に配置される。 この例に示した unsigned long long 除算以外のコードでも問題が発生するかどうかについては、未調査のため不明である。