IPL(Initial Program Loader)がプログラムをロードするようにする(03_day/harib00a)
新出アセンブリ
命令 | |
---|---|
JC |
jump if carry。キャリーフラグが1だったらジャンプする |
JNC |
jump if not carry |
JBE |
jump if below or equal。<= |
JB |
jump if below。< |
<identifier> EQU <value> |
const <identifier> = <value>; |
[ES:BX]
1 | MOV AL,[ES:BX] |
ES
はエクストラセグメント。BX
、ES
ともに16bit。アドレス指定に16bitしか使えないと困るから、[ES:BX]
で、ES*16+BX
のアドレス指定ができるようにしたらしい。なぜ*16なのかは不明。最大で0xFFFF0+0xFFFF=1114095
のアドレスが指定できる。
セグメントレジスタはアドレス指定に必須
省略可能だが、[123]
は[DS:123]
と解釈されていたらしい。よって、DS
を0にしないとアドレスが狂う。
起動
makefile
1 | ipl: ipl.nas |

今まで通り起動するとロードに失敗した。
https://qemu.weilnetz.de/doc/qemu-doc.html に書いてあるとおり、フロッピーディスクとしてイメージファイルを読むには-fda
オプションを使用する。
1 | PS> qemu-system-x86_64 -fda .\os.img |

何も表示されず、起動に成功した。
なお、途中の節はフロッピーの構造に合わせて読み込むためのアセンブリを書いているだけなのでパス。
OS本体を作る(03_day/harib00f)
haribote.sys
を別に作り、ipl.bin
からロードする。
OS本体をイメージファイルにコピーするには、mcopy
を使えば良い。
4.8 Mcopy
The mcopy command is used to copy MS-DOS files to and from Unix. It uses the following syntax:mcopy [-tnvm] MSDOSsourcefile
haribote.sys
がMSDOSsourcefileに当たるので、
1 | mcopy haribote.sys -i os.img :: |
-i
オプションは前回参照。
1 | default: ipl haribote |

画面モードをグラフィックスに切替(03_day/harib00g)
ビデオモード設定
詳細 | |
---|---|
AH |
0x00 |
AL |
0x03 =16色テキスト 80*25 |
0x13 =VGAグラフィックス、320*200*8bitカラー |
|
戻り値 | なし |
ファイル構成が複雑になってきたのでmakefileで変数を使うようにした。
1 | IPL_NAME=ipl10 |

32bitにするための準備(03_day/harib00h)
32bitのCコンパイラを使いたいが、BIOSは16bit用のアセンブリで書かれているため、互換性がない。そこでBIOSから得る情報は先に読み込み、メモリに格納しておく。
C言語導入(03_day/harib00i)
著者作のツールを使わない縛りなので、ここが一番たいへんだった。Cで書かれたプログラムをコンパイルした後、リンカスクリプトを使ってリンクし、asmhead.bin
と合わせて、haribote.sys
を作る必要がある。つまり、このようになる。
1 | asmhead.nas--(nasm)-> asmhead.bin --\ |
まず、asmhead.nas
、そのままではアセンブルに失敗した。
1 | $ nasm asmhead.nas -o asmhead.bin |
どうやら[]
のつくディレクティブは著者作のnask固有のようなので、この行を削除する。
次に問題となるのがリンカスクリプト、HariboteOSに合わせてバイナリを作らなければいけないので、P.460にある構造を作る必要がある。
私はリンカスクリプトなど全く知らないので、 https://vanya.jp.net/os/haribote.html こちらからお借りした。
1 | /* os.ld */ |
gccのオプションは、今回は32bitで作り、リンカスクリプトを指定するので、以下のオプションを使う。また、標準ライブラリは使わないので-nostdlib
もつける。
1 | https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html |
1 | IPL_NAME=ipl10 |

正常に起動したが、C言語側からHLTを呼び出していないので、このようにCPU使用率が100%になっている。
CからHLTを呼ぶ(03_day/harib00j)
1 | asmhead.nas--(nasm)-> asmhead.bin --\ |
例によって、asmhead.nas
と、naskfunc.nas
の[]
の行を削除。
1 | IPL_NAME=ipl10 |
ここで、新たなオプション、nasmの-f elf
、
https://www.nasm.us/doc/nasmdoc2.html#section-2.1.2
gccに入力するオブジェクトファイルなので、ELF(Executable and Linking Format)にアセンブルする必要がある。
エラーが出る。
1 | bootpack.c:(.text+0x7): undefined reference to `io_hlt' |
試しにnaskfunc.nas
の_io_hlt
をio_hlt
に置換したら、うまく行った。
1 | ; naskfunc |
これで良いかと思いきや、またエラーが出る。
1 | bootpack.c: undefined reference to `_GLOBAL_OFFSET_TABLE_' |
どうやら、GCCがセキュリティ確保のためにデフォルトで位置独立実行形式(PIE)となるようにしているらしい。今回のアセンブリでは位置が重要なので、-fno-pie
オプションでこれを無効化する。
位置独立コード(いちどくりつコード、英: position-independent code、PIC)または位置独立実行形式(いちどくりつじっこうけいしき、英: position-independent executable、PIE)とは、主記憶装置内のどこに置かれても絶対アドレスに関わらず正しく実行できる機械語の列である。
https://ja.wikipedia.org/wiki/位置独立コード
そうしてやっと起動できた。

確かにCPU使用率100%は改善されている。
おわりに
今回はいままでで一番大変だった。特に、著者作ツールを使わないせいでかなり調べることとなった。
参考文献
- https://qemu.weilnetz.de/doc/qemu-doc.html
- https://www.gnu.org/software/mtools/manual/mtools.html
- https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options
- https://stackoverflow.com/questions/45422374/undefined-reference-to-global-offset-table-only-when-generating-binaries
- https://vanya.jp.net/os/haribote.html