Hatena::ブログ(Diary)

big-eyed-hamsterの日記

2009-01-06

30日でできる!OS自作入門を Linux & GAS で行う (2日目)

というわけで、どうみても前の更新から5日以上たっているけれども2日目の説明を(笑

2日目で行うことは、

  1. 1日目で .byte、.word、.intでバイナリ直打ちしていた箇所をプログラムに置き換える
  2. リンカスクリプトを書く。
  3. Makefileアセンブルとディスクイメージ作成を自動化する

という3点である。1は、OS自作本を見ればなんとなくできてしまうだろう。また、3についても、 Linux 上でプログラム経験がある方であれば、あまり難しくないだろう。問題は2である。ユーザランドプログラムを書く用途でgccを使っていると、自分でリンカスクリプトを書く機会はなかなかない。せっかくなので、これを機にリンカスクリプトを書いてみよう(ToDo:説明増やす。今は寝る)。

  1 OUTPUT_FORMAT(binary)
  2 
  3 OUTPUT_ARCH(i386)
  4 
  5 SECTIONS {
  6 . = 0x7c00;
  7 .text : { *(.text) }
  8 }
  9 

このリンカスクリプトを使ってバイナリを生成するには、 -T オプションを使う。

 ld (入力オブジェクトファイル名) -T (リンカスクリプト) -o (出力するバイナリ)

うまくいくと、1日目と変わらない起動画面が出てくる。

f:id:big-eyed-hamster:20081230055038j:image

というわけで、詳細についてはソースコードOS自作本を見て頑張ってほしい。君ならできるはず!

ソースコードはこちら

Makefile

  1 IMG=helloos.img
  2 IPL=ipl.bin
  3 
  4 all: ipl.s
  5         make ipl
  6         make img
  7         make run
  8 
  9 img: $(IPL)
 10         mformat -f 1440 -C -B $(IPL) -i $(IMG) ::
 11 
 12 ipl: $(IPL:%.bin=%.o)
 13         ld $^  -T binary.ls -o $(IPL)
 14 
 15 run: $(IMG)
 16         qemu -m 32 -localtime -std-vga -hda ./$(IMG)
 17 
 18 clean:
 19         rm -f $(IMG) $(IPL) $(IPL:%.bin=%.o)
 20 

ipl.s

  1 // hello-os ver.gas
  2 // This program is going to be loaded at 0x7c00
  3 
  4 // $base_address = 0x7c00
  5 base_address:
  6     .code16
  7 
  8     jmp entry
  9     .byte   0x90
 10     .ascii  "HelloIpl"
 11     .word   512
 12     .byte   1
 13     .word   1
 14     .byte   2
 15     .word   224
 16     .word   2880
 17     .byte   0xf0
 18     .word   9
 19     .word   18
 20     .word   2
 21     .int    0
 22     .int    2880
 23     .byte   0,0,0x29
 24     .int    0xffffffff
 25     .ascii  "HELLO-OS   "
 26     .ascii  "FAT12   "
 27     .skip   18,0
 28 
 29 entry:
 30     movw    $0,%ax
 31     movw    %ax,%ss
 32     movw    $base_address,%sp
 33     movw    %ax,%ds
 34     movw    %ax,%es
 35 
 36     // label のアドレスをさすには、$msgとする
 37     movw    $msg,%si
 38 
 39     // 間違いなくアドレッシングがおかしい
 40     // siレジスタのさしている先がおかしい
 41     // $ つけわすれだった ;_;
 42 putloop:
 43     movb    (%si),%al
 44     add     $0x01,%si
 45     cmpb    $0x00,%al
 46     je      fin
 47     movb    $0x0e,%ah
 48     movw    $0x0015,%bx
 49     int     $0x10
 50     jmp     putloop
 51 
 52 fin:
 53     hlt
 54     jmp     fin
 55 
 56 msg:
 57     .byte   0x0a,0x0a
 58     .ascii  "hello,world"
 59     .byte   0x0a
 60     .byte   0x00
 61 
 62     .org    0x1fe
 63     .byte   0x55,0xaa

2008-12-29

30日でできる!OS自作入門を Linux & GAS で行う (1日目)

gcc & as in Linux環境 で OS自作入門したい!と思ったので、そのために環境構築してみた。モチベーションとしては、

  1. Linuxコンパイルgcc で行われているから、gccで生成したバイナリをそのまま使えた方がlinuxも理解できるかも。
  2. ブートローダをGASで書けたらとても素敵だよね。

といったあたり。

しかし、OS自作本は Windows 向けに開発環境としてコンパイルされたバイナリのみが提供されているため、gasなどで試そうとしてもソースは違うわ、バイナリは違うわで動かない、やる気なくす、本は放置となってしまう。それじゃあもったいないということで、gas & as で OS自作入門を試してみようじゃないか、試すのだったら後でやる人がスムーズに同じことできるようにメモをとってったらいいんじゃないか、という趣旨。

教科書

いわずもがな、30日でできるOS自作入門。

30日でできる! OS自作入門

30日でできる! OS自作入門

加えて、Linux環境で「30日でできる!OS自作入門」を試していらっしゃる touch さんの まとめ blog

http://www14.big.or.jp/~touch/blog/os/

環境

Ubuntu 8.04 LTS Desktop (Kernel 2.6.26.8)

基本的に Linux 環境で、かつ gcc と make のバージョン(後述)が合ってる環境ならいけるのではないかな?

代替品の用意

どの道具が何を行っているかを、以下にまとめる。

種類ツール名
バイナリエディタhexer (emacs 使いの方は emacsバイナリ編集モードが良いかも)
Dosのディスクイメージ生成プログラムmformat
ビルド用ユーティリティGNU make 3.81
コンパイラgcc 4.2.4
アセンブラGNU Assembler 2.18.0
リンカGNU ld 2.18.0.20080103

早速、上記プログラムインストールする。

 sudo aptitude install build-essential hexer mtools qemu

1日目をやってみる

バイナリエディタでイメージ作成

まず、viライクなバイナリエディタhexerを起動して、ディスクイメージを作成。

hexer helloos.img

これは打ち込むだけなので対した苦労はない。できたら、

qemu -fda ./helloos.img

として起動する。Hello, world が出力されていたら正常に読み込まれている証拠。

GASでデータを配置

さて、ここからが本番。GASでデータを配置していく。問題は大きくわけて2つあって、

  1. GASで記述する(nasmではDWなどでデータを保存していくところを、.wordなどGASの記法に置換しながらかき進める必要がある)
  2. 記述したテキストファイルをasに食わせると実行可能バイナリ(elf)形式として吐き出される

と言う問題がある。1.は、OS自作入門メモ (1日目)を参考にすればいけるはず。対応表は以下の通り;

nasm(nask)gas
DB.byte
DW.word
DD.int
ORGなし
fresb.org

ソースファイルの入力が終了したら、asでアセンブルする。

as gen_image.s -o tmp.img

2.については、書き込み時にelfヘッダをスキップして書き込むことで解決する。elfヘッダが何バイトか調べるには、バイナリエディタでイメージファイルを開いて数えても楽しいけれど、readelfコマンドを使うと大変便利。

readelf -h tmp.img 
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0

先頭52バイトがelfヘッダで、その他にはヘッダは存在しないということがわかった。なので、これをスキップして別ファイルに書き込む。書き込みには、みなさんお馴染みddコマンドを使用する。

as gen_image.s -o tmp.img
dd if=tmp.img of=helloos.img skip=52 bytesize=1

最後に、helloos.imgを用いてqemuを起動する。

qemu -fda ./helloos.img

これで無事起動すれば、1日目は終了。

f:id:big-eyed-hamster:20081229234933j:image

なお、私の書いたソースコードはこちら↓

  1   .byte   0xeb,0x4e,0x90
  2   .ascii  "HelloIpl"
  3   .word   512
  4   .byte   1
  5   .word   1
  6   .byte   2
  7   .word   224
  8   .word   2880
  9   .byte   0xf0
 10   .word   9
 11   .word   18
 12   .word   2
 13   .int    0
 14   .int    2880
 15   .byte   0,0,0x29
 16   .int    0xffffffff
 17   .ascii  "HELLO-OS   "
 18   .ascii  "FAT12   "
 19   .skip   18,0
 20 
 21 // Entry Point of this program!!
 22   .byte   0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
 23   .byte   0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
 24   .byte   0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
 25   .byte   0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
 26   .byte   0xee, 0xf4, 0xeb, 0xfd
 27 
 28 // Data for message.
 29   .byte   0x0a, 0x0a
 30   .ascii  "hello,world,yeahhh!"
 31   .byte   0x0a
 32   .byte   0
 33   .org    0x1fe,0
 34 
 35   .byte   0x55, 0xaa
 36 
 37   .byte   0xf0,0xff,0xff,0x00,0x00,0x00,0x00,0x00
 38   .skip   4600
 39   .byte   0xf0,0xff,0xff,0x00,0x00,0x00,0x00,0x00
 40   .skip   1469432
 41