ごちゃごちゃしたIT勉強記録

自分用メモ。主にセキュリティで、その他色々書きたい。

30日OS自作入門-3日目(C言語導入)-

ちょっと気分を変えてブログの名前を変えてみました。

最近インフラ勉強会に参加しているのですが、セキュリティ以外の部分も色々やっていきたいなぁ、というところが芽生えまして。というところで、今後ともお付き合いいただければと思います。

さて、では始めていきます。
今回は、前回のつづきとしてC言語を導入し32ビットで動作するコードを書いていきます。とはいいつつ、まだまだアセンブリ多め。

 

今回のまとめ

3日目の後ろの方で、C言語を導入するところからになります。

で、本書とは違うツールを使用する場合には、作成するファイルであったり追加で必要となったりするファイルがあります。

そこらへんは以下のサイトを参考にして流れの確認やコマンドのオプション確認を行いました。

  

・流れの確認で参考にしたサイト

OS自作入門 3日目-1 【Linux】| 64bit環境での苦悩 | サラリーマンがハッカーを真剣に目指す

・コマンドの確認で使用したサイト

『30日でできる!OS自作入門』のメモ

 

んで、上のサイトはこの本を読み終えるまで非常に参考となります。私も逐一ここは確認しながらやっていこうと思います。

 

Haribote.img作成までの流れ

上で紹介したサイトにも流れは書いていますが、自分なりに図を起こしてみました。

どのコードがイメージファイルのどの部分に入ってくるのかイメージしやすいようにしてみました。特に、harib00iとharib00jの部分が本書で使用するツールを使わない場合になかなか難しいと思いますので、そこを中心に。

(作成する際のファイル名は、本書のものとはちょっと異なる(だいたい何のファイルかは想像がつくかと思います)ので、読み替えていただければ。

 

harib00i

まずは、harib00iで作成するイメージファイルの作成フローです

f:id:motojiroxx:20180610235430p:plain

作成したMakefileは以下の通り。上の図と比較しながら見ていただければ。

# Makefile for harib00i
bootpack.hrb: bootpack.c os.lds
    gcc -march=i486 -m32 -nostdlib -T os.lds bootpack.c -o bootpack.hrb

nasmhead.bin: nasmhead.nas
    nasm nasmhead.nas -o nasmhead.bin -l nasmhead.lst

ipl.bin: ipl.nas
    nasm ipl.nas -o ipl.bin

haribote.sys: nasmhead.bin bootpack.hrb
    cat nasmhead.bin bootpack.hrb > haribote.sys

.PHONY: run
run:
    qemu-system-i386 -fda hariboteos.img

.PHONY: remove
remove:
    rm *.bin *.lst *.sys *.hrb 

.PHONY: debug
debug:
    qemu-system-i386 -m 32 -localtime -vga std -fda hariboteos.img -gdb tcp::10000 -S &

hariboteos.img: ipl.bin haribote.sys
    mformat -f 1440 -C -B ipl.bin -i hariboteos.img ::
    mcopy -i hariboteos.img haribote.sys ::

 

 最後のhariboteos.imgを作成する際には、mformatとmcopyというコマンドを使っています(上記の参考サイトをみてやって見ました)。

一応、このコマンドが何をやっているのかをまとめておきます。

mformat -f 1440 -C -B ipl.bin -i hariboteos.img ::
    -f 1440 : サイズを指定、今回は1440byte
    -C : ディスクイメージを作成し、MS-DOSファイルシステムを構成する
    -B ipl.bin : ブートセクタを指定する。今回はipl.binがブートセクタ
    -i : よくわからない(image fileのiとか?と推測)

 ここでのmformatコマンドでは、1440byteのイメージファイルhariboteos.imgを作成し、ファイルシステムFAT12として、ブートセクタをipl.binに書かれている内容とする、ということをやっています。

FAT12の12の部分って「何ビットのクラスタ識別子を利用するか」という話だったんですね。。んでクラスタ識別子は「ファイルを何個まで格納できるようにするか」という話なので、2^12=4096個までファイルを格納できるファイルシステムFAT12ということでしょうね)

 

mcopy -i hariboteos.img haribote.sys ::
    -i : こちらもわからない(おそらくimage fileを指定したものだと思われる)

 mcopyコマンドでは、先ほどmformatで作成したイメージファイルhariboteos.imgのファイルシステム内にファイルを追加するということを行なっています。

追加するファイルはharibote.sysで、前回の記事で書いたFATの構成のRoot Directory部分にharibote.sysのファイル名を追加し、File Storage Spaceにharibote.sysのファイルの中身を記録しています。

ということで、xxdコマンドを使ってhariboteos.imgのファイル内をみてみます。

 

まずは、0x2600の部分にharibote.sysファイル名が書かれています。

f:id:motojiroxx:20180611003853p:plain

 

続いて、0x4200にharibote.sysの中身が書かれていることを確認します。

f:id:motojiroxx:20180611004008p:plain

 

個別に作成したharibote.sysの中身がこちら。

f:id:motojiroxx:20180611004157p:plain

多分同じになっているはずです。このような動きをmformatとmcopyのコマンドではやっています。

 

harib00j

次に、nasmfuncを加えたharib00jのイメージファイル作成フローです。

f:id:motojiroxx:20180610235455p:plain

作成したMakefileは以下の通り。こちらも同様に上の図を見ながら確認していただければ。

# Makefile for harib00j
bootpack.hrb: bootpack.c nasmfunc.o os.lds
    gcc -march=i486 -m32 -nostdlib -T os.lds nasmfunc.o bootpack.c -o bootpack.hrb

nasmhead.bin: nasmhead.nas
    nasm nasmhead.nas -o nasmhead.bin -l nasmhead.lst

nasmfunc.o: nasmfunc.nas
    nasm -f elf nasmfunc.nas -o nasmfunc.o -l nasmfunc.lst

ipl.bin: ipl.nas
    nasm ipl.nas -o ipl.bin

haribote.sys: nasmhead.bin bootpack.hrb
    cat nasmhead.bin bootpack.hrb > haribote.sys

.PHONY: run
run:
    qemu-system-i386 -fda hariboteos.img

.PHONY: remove
remove:
    rm *.bin *.lst *.sys *.hrb *.o 

.PHONY: debug
debug:
    qemu-system-i386 -m 32 -localtime -vga std -fda hariboteos.img -gdb tcp::10000 -S &

hariboteos.img: ipl.bin haribote.sys
    mformat -f 1440 -C -B ipl.bin -i hariboteos.img ::
    mcopy -i hariboteos.img haribote.sys ::

 

harib00iとharib00jの動作結果として、真っ黒の画面が出ていれば成功です(おそらく

 

bootpack.hrbを作成する際、gccを使用してbootpack.oとnasmfunc.oをos.ldsというリンカスクリプトを利用して生成しています。リンカスクリプトについては以下のサイトをみなさん参考にやっていたので、私も便乗しました。

https://vanya.jp.net/os/haribote.html#gcchrb

ただ、このリンカスクリプトの書き方も後でちゃんと確認しておこうと思います。

 

本当はここをldを使ってリンクをしたかったのですが、うまくいかなかったのでgccコマンドでまとめてやってしまっています。

これもちゃんとあとでldを使う場合にはどうしたらちゃんとうまくいくか確認してみようと思います。

 

ドツボにハマったところ

色々なサイトを見ていきながらコードを書いて、「いざ実行!」して見たのですが、なぜか画面が真っ黒にならず、一番最初の「Booting from floppy...」までの文字列が繰り返し表示される。。。

ひとまず、デバッグをして見たところ、なぜか0x7c00(ipl.binが置かれるメモリアドレス)と0xc200(nasmhead.binが置かれるメモリアドレス)を行ったり来たりしていました。

一応コードの間違いとかを確認しましたが、それを見つけられなかったので再び1からコードを書き直しました。書き直した方ではちゃんと動きました。

んで、何が間違っていたかというと、nasmheadの最後の部分がなんかおかしかったようです(hexみたらなんか違う。。。)。

なぜ繰り返したかはちょっとこの後デバッグしてみて確認しようと思います。

 

失敗したことと参考情報

特にharib00jの部分で色々とありましたので、そこをまとめておきます。

まず、nasmを使用している場合、nasmfunc.nasでは

  • [FORMAT "WCOFF"]と[FILE "nasmfunc.nas"]の部分は必要ない

実際にこれを書いた状態でアセンブルした場合、以下のようなエラーが出ます。

nasmfunc.nas:4: error: unrecognised directive [FORMAT]
nasmfunc.nas:9: error: unrecognised directive [FILE]

識別できないディレクティブがあるということですが、これらの行をコメントアウトすることで解決できます。

 

続いて、nasmfunc.nasのオブジェクトファイルを生成したのち、gccでbootpack.hrbを生成しようとしたところ、以下のようなエラーが吐かれました。

nasmfunc.o: file not recognized: File truncated

 

もともとMakefileに書いていたnasmのコマンドは以下の通りです。

nasm nasmfunc.nas -l nasmfunc.lst -o nasmfunc.o

 ということで、nasmfunc.oってどんなファイルになってるのかをfileコマンドで調べたところ、

nasmfunc.o: ISO-8859 text, with no line terminators

 となっていました。生成しなければいけないのはELF形式なので、こりゃだめだということでnasmfunc.nasアセンブルする際にコマンドのオプションを追加して解決できました(上記Makefileのnasmfunc.oの部分を参照のこと)

 

その後もエラーがでます。次はgccでbootpack.hrbを生成する際に、bootpack.cの部分で以下のようなエラーが出ました。

/tmp/ccjdiCmn.o: In function `HariMain':
bootpack.c:(.text+0x7): undefined reference to `io_hlt'

よくよく考えてみると、このエラーが出るのは当然かと。プロトタイプ宣言している関数が外部ファイルに定義されているものなのに、「外部ファイルから呼び出しますよー」という記述が一切ないですよね。

というわけで、bootpack.c内でプロトタイプ宣言されているio_hlt関数の先頭にexternを入れることで、「この関数は外部ファイルで定義されているますよー」という目印になります。これで無事解決。

んで、本書のダウンロードリンクから落としてきたソースにはexternがついていません。なので、これをそのまま写してgccコンパイルしたとしても通らない可能性が高いです。ご注意を。 

 

 

あと、harib00jで作成したイメージをgdbでリモートデバッグしてみたのですが、ちょっと嫌な予感がしています。。

まぁ、これについては詰まった時にまた考えることにします。

 

ちゃんと動くまでかなり時間を要しましたが、これでちゃんと先に進めそうです。

ただ、ここで3回ほどソースコードを全部書き直したりしたので、コードの流れがある程度把握できたと思います。

うまく動かない場合には一からコードを書き直すのもありだと思います。