読者です 読者をやめる 読者になる 読者になる

yukke_longriders

ぼちぼちがんばる

LinuxでOS自作入門 1日目

OS自作

始める前に

本編ではいろいろ準備があるが、特に関係ないので飛ばす。

本体のプログラムを作っていくのだが、いきなりバイナリで数字をひたすら打ち込む。のも嫌なのでスキップ。

まず試しに

ここで nask を NASM に書き直していきます。これは簡単で4か所あり RESB (数字)TIMES (数字) DB 0 にすればいいです。
RESB は NASM では推奨されいていないようです。
それと最後の方にある 0x1fe-$0x1fe-($-$$) に変えます。
nask では$はこの行が先頭から何バイト目かを返す変数となります。

helloos1.nasm

DB    0xeb, 0x4e, 0x90
DB    "HELLOIPL"
DW    512
DB    1
DW    1
DB    2
DW    224
DW    2880
DB    0xf0
DW    9
DW    18
DW    2
DD    0
DD    2880
DB    0,0,0x29
DD    0xffffffff
DB    "HELLO-OS   "
DB    "FAT12   "
TIMES 18 DB    0

;プログラム本体
DB    0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
DB    0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
DB    0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
DB    0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
DB    0xee, 0xf4, 0xeb, 0xfd

; メッセージ部分
DB    0x0a, 0x0a
DB    "hello, NASM"
DB    0x0a
DB    0

TIMES 0x1fe-($-$$) DB    0

DB    0x55, 0xaa

; 以下はブートセクタ以外の部分の記述
DB    0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
TIMES 4600 DB    0
DB    0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
TIMES 1469432 DB    0

これをOSイメージにして実行します。
-fdaフロッピーディスクとして実行するオプションです。

$ nasm helloos1.asm -o helloos1asm.img
$ qemu-system-x86_64 -fda helloos1asm.img

f:id:yukke42:20161212233003p:plain
(メッセージは変えてみた)

本編

ここから GAS に書き直していきます。
まず、 BW DD をそれぞれ .word .intにします。それぞれは、16bit(2byte),32bit(4byte) の値を格納しその領域を確保する命令。
一番多い DB は、次に続くものが数字なら .byte に、文字列なら .ascii にします。これらも8bit(1byte), 文字列に対し同様に動作する命令です。
最後は0で埋める命令の TIMESskip にし、追加した DB 0は消します。そして 最後の方にある -($-$$)も消します。 数字の後に、0 で埋めるということを明記します。

そうするとこうなります。
helloos1.s

.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, GAS"
.byte   0x0a
.byte   0

.org    0x1fe # 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

同様にOSイメージにして実行します。

$ gcc helloos1.s -nostdlib -Tlnk.ls -o helloos1s.img
$ qemu-system-x86_64 -fda helloos1s.img

(これのオプションがいる理由はわかりません..)
〜追記(2016/12/14)〜
-nostdlib は標準ライブラリをリンクしないということだそうです。

f:id:yukke42:20161212233018p:plain

最後に

環境を整えるのに知らないことが多すぎます。なので本編ではさらっと終わっているのに時間は思ったよりかかりました。
時間はかなりかかりそうですが少しずつ進めていきたいと思います。

補足

これは2日目の先取りとなるのですが、毎回OSイメージを作成&実行するのを入力して試行錯誤するのはめんどうになります。
そこで Makefile というものを利用します。

Makefile で保存します。

helloos1asm.img:
	nasm helloos1.asm -o helloos1asm.img

runnasm:
	make helloos1asm.img
	qemu-system-x86_64 -fda helloos1asm.img
	rm helloos1asm.img

helloos1s.img:
	gcc helloos1.s -nostdlib -Tlnk.ls -o helloos1s.img

rungas:
	make helloos1s.img
	qemu-system-x86_64 -fda helloos1s.img
	rm helloos1s.img

〜追記(2016/12/13)〜
Make について誤解していたようですね。(今でも微妙ですが)書き直します。

IMG = helloos2s.img
GAS = helloos2.s

img:
	gcc $(GAS) -nostdlib -T lnk.ls -o $(IMG)

rungas:
	make img
	qemu-system-x86_64 -fda $(IMG)
	rm $(IMG)

ファイル名の書き直す箇所が少なくなります。
〜追記終わり〜

こうすれば

$ make rungas

とか

$ make runnasm

と入力すればアセンブリファイルからイメージ作成、実行まで一度にできるようになります。
ファイル名を変更すれば毎回利用できます。
(.img は残っているとうまく上書きされずにそのまま実行してしまうみたいなので、一応毎回消しときます。)

~追記(2016/12/15)~
最後のページにあった記述に関することで、今日の分のようにそのまま命令で書いてもいいのですが、リンカスクリプトで記述もできるようなので載せときます。(3日目以降の分から変更されています。)
main関数だよと宣言する.textが2行目に追加されています。
lnk.ls

OUTPUT_FORMAT("binary");
IPLBASE = 0x7c00;

SECTIONS {
        . = IPLBASE;
        .text :{*(.text)}
        . = IPLBASE + 0x1fe;
        .sign : {SHORT(0xaa55)}
}