OS自作入門 onLinux 2日目
OS自作、2日目です。試験中なのは秘密
2日目は結構楽だったので、まとめていきます。
実は、IPLを読み込む位置がうまくいかず、バイナリを解読してたんですが…
==== まずはソースコードをGAS用に変換します。
.code16 .text jmp entry .byte 0x90 .ascii "HELLOIPL" # ブートセクタの名前 .word 512 # 1セクタの大きさ .byte 1 # クラスタの大きさ .word 1 # FATがどこから始まるか .byte 2 # FATの個数 .word 224 # ルートディレクトリのサイズ .word 2880 # このドライブの大きさ .byte 0xf0 # メディアのタイプ .word 9 # FAT領域の長さ .word 18 # 1トラックにいくつのセクタがあるか .word 2 # ヘッドの数 .int 0 # 必ず0 .int 2880 # ドライブのサイズ .byte 0, 0, 0x29 .int 0xffffffff # ボリュームシリアル番号 .ascii "HELLO-OS " # ディスクの名前 .ascii "FAT12 " # フォーマットの名前 .skip 18, 0x00 # 18バイト空ける # プログラム本体 entry: movw $0, %ax # レジスタ初期化 movw %ax, %ss movw $0x7c00, %sp movw %ax, %ds movw %ax, %es movw $msg, %si putloop: movb (%si), %al addw $1, %si cmpb $0, %al je fin movb $0x0e, %ah # 一文字表示BIOSコール movw $15, %bx # カラーコード int $0x10 # ビデオBIOS呼び出し jmp putloop fin: hlt jmp fin .data msg: .string "Hello, world!\n"
まずは、コメントがついてなかったので、すべてつけました。
今回はちょっとずつGASのソースも解説していきます。
1行目.code16ディレクティブは、16bit用のバイナリを吐きます。
.byte、.word、.int、.ascii、.skipは前回説明したので省略。
26行目からプログラム本体です。
mov命令に"w"や"b"とついていますが、GASではオペランドが2バイト(16bit)なら"w"を、
1バイト(8bit)なら"b"を命令のあとにつけることになってます。
ちなみに、4バイト(32bit)なら"l"、8バイト(64bit)なら"q"です。
あと、GASではデフォルトではAT&T記法なので、Intel記法のアセンブラと
ソースオペランドとデスティネーションオペランドが逆になっているのに注意。
(例) AT&T:movw $0, %ax → Intel:mov ax, 0
33行目でmsgのアドレスをsiレジスタに入れていますが、
ラベルのアドレスをレジスタにぶち込むときは"$"をつける。
35行目、siレジスタの数値をアドレスをして利用するときは
nasmでは[](大括弧)でくくるが、GASでは()(中括弧)でくくる。
※これはアドレッシングモードという使い方だが、厳密な説明は省く
48行目で.stringディレクティブをつかっているが、これと.asciiの違いは
「最後に自動で"\0"が入るかどうか」だけ。
.stringなら、勝手にヌルバイトが入る。
あとはOS自作本通りの説明です。
このIPLのソースだけでは、OS自作本にあるように0x7c00にロードしたり
できません。最後の0x55AAも消しましたし、1440KBまで埋めるような記述もありません。
まずは、リンカスクリプトを拡張します。
OUTPUT_FORMAT("binary"); IPLBASE = 0x7c00; SECTIONS { . = IPLBASE; .text : {*(.text)} .data : {*(.data)} . = IPLBASE + 510; .sign : {SHORT(0xaa55)} }
2行目に、IPLBASEという変数を定義します。
リンカスクリプトは、3行目から始まるSECTIONSコマンドで、バイナリを制御できます。
詳しいことはあまり触れませんので、興味があったらこちらをどうぞ。
さて、それではMakefileを作ります。
IMG=os.img IPL=ipl.bin all : ipl.s make ipl make img make run os.img : $(IPL) mformat -f 1440 -C -B $(IPL) -i $(IMG) :: ipl.bin : ipl.s ipl.ls gcc ipl.s -nostdlib -Tipl.ls -o $(IPL) run : $(IMG) qemu -m 32 -localtime -vga std -fda $(IMG) ipl :; make ipl.bin img :; make os.img
ファイル名は以下のようになっています。
IPLのソース:ipl.s
リンカスクリプト:ipl.ls
OSイメージ:os.img
OSイメージを作る時に、mformatコマンドを用いています。
これで1440KBまで埋めます。
また、QEMUに新しいオプションを色々つけています。
-m:RAMのサイズ(MB単位)
-localtime:ホストの時刻をゲストに設定する
-vga:VGAグラフィックスカードを設定する(stdで標準)
これで準備は整いました。
$ make run
前回と何の変化もありませんが、できました。
3日目はちょっと大変なんですよね。頑張ります。