はじめに
表題の本[1]はとても親切に書かれていて,順に追っていけば問題なく進めていけるのですが,タイプミスなど自分の不注意でエラーになることがあります.そんなときの対応も含めて勉強になるので,恥を忍んでメモをしていきます.
内容は,随時追加してきます.
なお,私が自爆した内容であり,書籍の記載のせいではないことをここで強調しておきます.
6th step もう一度,Hello World!
6-1 make エラー
症状
> cd os
> make
/usr/local/bin/h8300-elf-gcc startup.o main.o lib.o serial.o -o kozos -Wall -mh -nostdinc -nostdlib -fno-builtin -I. -Os -DKOZOS -static -T ld.scr -L.
/usr/local/lib/gcc/h8300-elf/8.2.0/../../../../h8300-elf/bin/ld:ld.scr:33: warning: memory region `data' not declared
/usr/local/lib/gcc/h8300-elf/8.2.0/../../../../h8300-elf/bin/ld: kozos section `.text.startup' will not fit in region `ram'
/usr/local/lib/gcc/h8300-elf/8.2.0/../../../../h8300-elf/bin/ld: region `ram' overflowed by 122 bytes
collect2: error: ld returned 1 exit status
Makefile:42: ターゲット 'kozos' のレシピで失敗しました
make: *** [kozos] エラー 1
原因と対策
"region `ram' overflowed" と言われている通りで,リンカスクリプトのRAM領域のサイズを間違えて小さくしすぎていたため,収まらないとエラーを出してくれていました.
MEMORY
{
ram(rwx) : o = 0xfffc20, l = 0x000300 /* ここは,0x003f000 が正しい */
stack(rw) : o = 0xffff00, l = 0x000000 /* end of RAM */
}
6-2 エントリーポイントのアドレスが 0x0 になってしまう
症状
> readelf -a kozos.elf
ELF ヘッダ:
マジック: 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00
クラス: ELF32
データ: 2 の補数、ビッグエンディアン
バージョン: 1 (current)
OS/ABI: UNIX - System V
ABI バージョン: 0
型: EXEC (実行可能ファイル)
マシン: Renesas H8/300
バージョン: 0x1
エントリポイントアドレス: 0x0
プログラムの開始ヘッダ: 52 (バイト)
セクションヘッダ始点: 2932 (バイト)
フラグ: 0x810000
このヘッダのサイズ: 52 (バイト)
プログラムヘッダサイズ: 32 (バイト)
プログラムヘッダ数: 4
セクションヘッダ: 40 (バイト)
セクションヘッダサイズ: 9
セクションヘッダ文字列表索引: 8
原因と対策
- .SECTIONS 内の ROM 領域の定義は削除していた.(これは正しい)
- かつ,リンカスクリプトの .text セクションの配置先指定が, > ROM のままになっていた
現象としては,リンカが,未定義の領域を 0x0 として処理していたようです.
6.3 OSが実行できない
OS の ELF をロードして run すると,エントリーポイントの表示が正しくなく,そのまま固まります.readelf -a kozos で表示されるエントリーポイントは正しいことを確認しました (0x00ff0c20).
kzload> load
XMODEM receive succeeded.
kzload> run
starting from entry point: 20kzload (kozos boot loader) started.
kzload>
原因と対策
エントリーポイントが 20 と表示されるのは, 0x00ff0c20 のLSB側だけが切り取られて表示されているように見えます.elf_read() の返値がおかしいのではないかと予想し,ソースを確認したところ,返値の型に間違いが見つかりました.
char elf_load(char *buf) /* 正しくは char *elf_load(char *buf) */
ポインタを返すべきところが char になっていたので,MSB側が切り捨てられていたようです.ヘッダも同様に誤りがあったので修正したところ,うまく動きました.
7th step 割込み処理を実装する
7.1 kozos を load すると bootloader に戻ってしまう
症状
kzload> load
XMODEM receive succeeded.
kzload> run
starting from entry point: ffc020
kozos boot succeeded!
> kzload (kozos boot loader) started.
kzload> a
原因と対策
割込みハンドラの入り口で,_interrupt に渡すスタックポインタを間違えて,@ が余計についていました.さらに,割込みベクタを設定する vector.c の NULL の数が8個少なかったために,SCIの割込みベクタがずれていました.おそらく 0000 に飛ばされて,bootloader に戻っていたのだと思います.
.global _intr_serintr
.type _intr_serintr,@function
_intr_serintr:
mov.l er6,@-er7
mov.l er5,@-er7
mov.l er4,@-er7
mov.l er3,@-er7
mov.l er2,@-er7
mov.l er1,@-er7
mov.l er0,@-er7
mov.l er7,@er1 ; 正しくは mov.l er7,er1
mov.w #SOFTVEC_TYPE_SOFTERR,r0
jsr @_interrupt
mov.l @er7+,er0
mov.l @er7+,er1
mov.l @er7+,er2
mov.l @er7+,er3
mov.l @er7+,er4
mov.l @er7+,er5
mov.l @er7+,er6
rte
参考文献
[1] 坂井弘亮, 「12ステップで作る組み込みOS自作入門」, カットシステム