OS自作入門 onLinux 1日目
OS自作を夢見る初心者が手にする本、「30日でできる!OS自作入門」です。
この本自体については賛否両論あるのですが、やはりこれほど単純にOSの作り方が
説明された本はないと思います。
反面C言語やアセンブリ言語についての説明が不適当な箇所が
見られたりするということもあります。この本だけでOSが作れるかというと、
「ノー」と言わざるを得ません。
ですが、一度手に取ってほしい本ではあります。
この本だけにしかない魅力があります。
さて、この本最大のネックである「Windowsの開発」なのですが、
これを今回はLinuxで行ってみたいと思います。
同じようなことをやった他の方もいますし、ブログ記事も既に存在します。
実は俺自身が備忘録としてやっているだけなのは秘密
い、いや、きっとここでしか得られない情報があるはず!はず!
というわけで、拙速ながらもゆっくりとやっていきたいなーと思います。
==== ○バイナリエディタを使おう!
何はともあれ、まずはバイナリエディタの用意です。
Linuxで使えるバイナリエディタは
・hex
・hi
・bvi
・GHex
等々たくさんあるようですが、今回は俺の好み(?)でbviを採用します。
bviとは、viライクのバイナリエディタです。
Linuxをご存じの皆さんには、viの説明は要りませんね。
操作は基本的にviと同じです。ただし、書き込み操作の前には:set memmoveが必要です。
俺は一応ながらvimerの端くれです。たぶん。
:wq、:q!、a、i、r、xくらいしか使わないので、あとのことは知りません。
まずはbviをインストールします。当方の環境はLinux Mint 11です。
$ sudo apt-get install bvi
初期設定では、編集画面の横幅が16バイトになっておらず、
とても見づらいので設定します。
$ vi ~/.bvirc
(~/.bvircの内容)
set cm=16
set memmove
bviもvi同様、ホームフォルダの.bvircに書き込めば設定できます。
cmは一行に表示されるバイト数です。16にします。
さらに、.bvircでmemmoveをセットしておけば、編集時に入力する必要がなく、
非常に助かります。
○OSを作ろう!
続いて、自作本通り0x168000バイトを手で入力しましょう^^;
完成図
ちゃんと最後まで入力したんですよ
と言いたいところですが、ハッキリ言って俺には0x168000バイトも手で入力する
根気もありませんし、たとえセロテープで「0」キーをはりつけたとしても、
入力が終わるまで待つ忍耐力はありません。
#include <stdio.h> #include <ctype.h> int main(int argc, char **argv) { FILE *fp; char null[1] = "\0"; // open file if(!(fp = fopen(argv[1], "ab"))) { printf("Error to open file.\n"); return 0; } long pos, max = 0xFF << 1; // get file size pos = ftell( fp ); if( argc > 2 ) { max = atoi( argv[2] ); } // write null data printf("Fill %ld to %ld\n", pos, max); int i; for( i = pos; i < max; i++ ) { fwrite( null, 1, 1, fp ); } printf("Succeeded!\n"); return 0; }
これをコンパイルします。ソースの解説は省略。。。
$ gcc -o fat fat.c
$ ./fat helloos.img 1474560
Fill xxx to 1474560
Suceeded!
あ、ソースファイルの名前はfat.cにしておきました。こういうファイル肥大化ソフトは
fatって名前のことが多い気がします。
helloos.imgは、あのバイナリです。
0x001400辺りを過ぎるとすべて00になるので、そこまでは手入力して
あとはfatを使って残りを0x168000まですべて00で自動で埋めます。
ちなみに、1474560は何かというと、0x168000の10進数表記です。
$ python
>>> 0x168000
1474560
で調べました。python便利。
本来は、この程度はC言語じゃなくてスクリプト言語を使うべきなんでしょうが、
まともに使えるのがC言語くらいしかないので…(汗
さて、無事にバイナリイメージができたので、起動します。
そうか、QEMUの準備か。
○QEMUを使おう!
とりあえずインストールしましょう。
$ sudo apt-get install qemu-kvm
$ qemu -fda helloos.img
無事、起動できました。
○GASでアセンブルしてみよう!
まずは、nask用に書かれたソースをGAS用に直します。
.code16 .globl _start _start: .byte 0xeb, 0x4e, 0x90 .ascii "HELLOIPL" .word 512 .byte 1 .word 1 .byte 2 .word 224 .word 2880 .byte 0xf0 .word 9 .word 18 .word 2 .int 0 .int 2880 .byte 0, 0, 0x29 .int 0xffffffff .ascii "HELLO-OS " .ascii "FAT12 " .skip 18, 0x00 .byte 0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c .byte 0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a .byte 0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09 .byte 0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb .byte 0xee, 0xf4, 0xeb, 0xfd .byte 0x0a, 0x0a .ascii "hello, world" .byte 0x0a .byte 0 .org 0x1fe, 0x00 .byte 0x55, 0xaa .byte 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 .skip 4600, 0x00 .byte 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 .skip 1469432, 0x00
naskとの対応は以下のようになります。
DB -> .byte
DW -> .word
DD -> .int
また、.asciiは文字列を置くときに使います。機能的には.byteと同じです。
.skipは.skip [バイト数], [データ]と使う事で、指定したデータで指定バイト数だけ埋めます。
そのほかの説明は省略します。
これをアセンブルします。アセンブラはGCC付属のasを使います。
ところが、GCCは自動的にELFフォーマットで出力するので、
これをバイナリ出力にするために、リンカスクリプトを書きます。
$ vi lnk.ls
(lnk.lsの内容)
OUTPUT_FORMAT("binary")
リンカスクリプトとは、GCCでコンパイルするときに読み込むと、
バイナリレベルでいろいろと弄ることのできる設定ファイルみたいなものです。
OUTPUT_FORMAT("binary")で、ELFではなくバイナリをそのまま吐きます。
では、コンパイルしましょう。
$ gcc -nostdlib -o os.img temp.s -Tlnk.ls
-nostdlibオプションは、標準ライブラリをリンクしないという意味です。
今回は、temp.sという名前で保存したソースから、os.imgというバイナリを得ます。
-Tオプションでリンカスクリプトを指定します。
このように、アセンブリに移行することができました。
これでアセンブリが使えるようになりました。
1日目はこれくらいで終了ー。
何か間違いやご要望等がありましたら、遠慮なくご指摘お願いします。