前回はVimをバイナリエディタとして使って直接フロッピーディスクのイメージを作った。
今回はアセンブラを使ってフロッピーディスクのイメージを作ってみる。
Binutilsのインストール
本ではNASMに似たnaskという著者作のアセンブラを使ってるけど、やっぱりアセンブラでよく知られているのは、GNUのアセンブラ(gas)。
ということで、自分はnaskではなくgasを使ってみた。
gasはBinutilsというツール群に含まれている。
そこで、Binutilsをインストール。
Binutils - GNU Project - Free Software Foundation
インストールは簡単で、tarボールを落としてきて展開したら、configureスクリプトを実行してmakeするだけ。
$ tar zxvf binutils-2.28.tar.gz $ cd binutils-2.28 $ ./configure --program-prefix=i386-elf- --target=i386-elf --disable-nls $ make $ sudo make install
configureスクリプトで--program-prefix
オプションをつけると、各ツールの頭に指定したプレフィクスがつく。
今回はi386-elf用のアセンブラその他を作るので、i386-elf-
というプレフィクスをつけている。
(そうしないと、他のアーキテクチャ向けのアセンブラを作ったときに、名前がぶつかる)
また、--target
オプションで対象のアーキテクチャを指定している。
あと、--disable-nls
というオプションをつけているけど、これはNative Language Supportを無効にするもの。
このオプションをつけなかった場合、libintl.hが見つからないというエラーが出たので、つけている。
(このヘッダファイルはMacでQEMUのビルドをしてみた。 - いものやま。に書いたgettextの提供するヘッダファイルなので、同じようにインクルードパスを通してやるのでもOKのはず)
何はともあれ、これでBintuilsのインストールは完了。
i386-elf向けのアセンブラはi386-elf-as
というコマンドでインストールされている。
アセンブラソースの作成
Binutilsもインストールできたので、次はアセンブラソースの作成。
といっても、アセンブラでコードを書くのではなく、バイナリエディタと同じように、データを直接作ってみる。
gasの場合、.byte
や.int
といった擬似命令(ディレクティブ)を使うことで、バイナリデータを直接書くことが出来る。
また、.skip
という擬似命令を使うと、指定したサイズだけ隙間を作ることが出来る。
それらを使って書いたコードが、以下:
.byte 0xeb, 0x4e, 0x90, 0x48, 0x45, 0x4c, 0x4c, 0x4f .byte 0x49, 0x50, 0x4c, 0x00, 0x02, 0x01, 0x01, 0x00 .byte 0x02, 0xe0, 0x00, 0x40, 0x0b, 0xf0, 0x09, 0x00 .byte 0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 .byte 0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x29, 0xff .byte 0xff, 0xff, 0xff, 0x48, 0x45, 0x4c, 0x4c, 0x4f .byte 0x2d, 0x4f, 0x53, 0x20, 0x20, 0x20, 0x46, 0x41 .byte 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00 .skip 16, 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, 0x0a, 0x0a, 0x68, 0x65 .byte 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72 .byte 0x6c, 0x64, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 .skip 368, 0x00 .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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
これをhello-os.sというファイルに保存すれば、ソースは完成。
asによるアセンブル
アセンブラソースが出来たので、これをasでアセンブルしてやる。
$ i386-elf-as -o hello-os.o hello-os.s
問題なくアセンブルが終われば、hello-os.oというオブジェクトファイルが生成される。
objcopyによるバイナリファイルの生成
ただ、これでフロッピーディスクのイメージが出来たかというと、そうではなく。
実際、生成されたhello-os.oの内容を表示してみると、以下のとおり:
$ hexdump -C hello-os.o |less 00000000 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 |.ELF............| 00000010 01 00 03 00 01 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 a4 80 16 00 00 00 00 00 34 00 00 00 00 00 28 00 |........4.....(.| 00000030 07 00 06 00 eb 4e 90 48 45 4c 4c 4f 49 50 4c 00 |.....N.HELLOIPL.| 00000040 02 01 01 00 02 e0 00 40 0b f0 09 00 12 00 02 00 |.......@........| 00000050 00 00 00 00 40 0b 00 00 00 00 29 ff ff ff ff 48 |....@.....)....H| 00000060 45 4c 4c 4f 2d 4f 53 20 20 20 46 41 54 31 32 20 |ELLO-OS FAT12 | 00000070 20 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ..............| 00000080 00 00 00 00 b8 00 00 8e d0 bc 00 7c 8e d8 8e c0 |...........|....| 00000090 be 74 7c 8a 04 83 c6 01 3c 00 74 09 b4 0e bb 0f |.t|.....<.t.....| 000000a0 00 cd 10 eb ee f4 eb fd 0a 0a 68 65 6c 6c 6f 2c |..........hello,| 000000b0 20 77 6f 72 6c 64 0a 00 00 00 00 00 00 00 00 00 | world..........| 000000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00000230 00 00 55 aa f0 ff ff 00 00 00 00 00 00 00 00 00 |..U.............| 00000240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00001430 00 00 00 00 f0 ff ff 00 00 00 00 00 00 00 00 00 |................| 00001440 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00168050 03 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00168060 03 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00168070 03 00 03 00 00 00 2e 73 79 6d 74 61 62 00 2e 73 |.......symtab..s| 00168080 74 72 74 61 62 00 2e 73 68 73 74 72 74 61 62 00 |trtab..shstrtab.| 00168090 2e 74 65 78 74 00 2e 64 61 74 61 00 2e 62 73 73 |.text..data..bss| 001680a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 001680c0 00 00 00 00 00 00 00 00 00 00 00 00 1b 00 00 00 |................| 001680d0 01 00 00 00 06 00 00 00 00 00 00 00 34 00 00 00 |............4...| 001680e0 00 80 16 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 001680f0 00 00 00 00 21 00 00 00 01 00 00 00 03 00 00 00 |....!...........| 00168100 00 00 00 00 34 80 16 00 00 00 00 00 00 00 00 00 |....4...........| 00168110 00 00 00 00 01 00 00 00 00 00 00 00 27 00 00 00 |............'...| 00168120 08 00 00 00 03 00 00 00 00 00 00 00 34 80 16 00 |............4...| 00168130 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 00168140 00 00 00 00 01 00 00 00 02 00 00 00 00 00 00 00 |................| 00168150 00 00 00 00 34 80 16 00 40 00 00 00 05 00 00 00 |....4...@.......| 00168160 04 00 00 00 04 00 00 00 10 00 00 00 09 00 00 00 |................| 00168170 03 00 00 00 00 00 00 00 00 00 00 00 74 80 16 00 |............t...| 00168180 01 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 00168190 00 00 00 00 11 00 00 00 03 00 00 00 00 00 00 00 |................| 001681a0 00 00 00 00 75 80 16 00 2c 00 00 00 00 00 00 00 |....u...,.......| 001681b0 00 00 00 00 01 00 00 00 00 00 00 00 |............| 001681bc
見てのとおり、アセンブラに書いた内容だけではなく、なんか余計なデータが追加されているのが分かると思う。
これは、オブジェクトファイルが生のバイナリデータではなく、ELF形式のデータになっているため。
どのメモリにロードすべきかや、シンボルの情報、デバッグ情報なんかが一緒に詰め込まれている。
(ちなみに、アセンブラに書いた内容は0x34から始まっている)
普通のプログラムであれば、OSがこれらの情報を読み取って、適切なアドレスにロードしてくれるんだけど、ここではそういったローダはいないので、生のバイナリデータの形に自前で展開してやらないといけない。
ただ、Binutilsにはobjcopyというバイナリファイルの形式を変換するツールが含まれているので、これを使うことでオブジェクトファイルを生のバイナリデータに変換することが出来る。
(※もちろん、リンクされてすべてのシンボルが解決されていないとダメ)
以下のコマンドを実行:
$ i386-elf-objcopy -O binary hello-os.o hello-os.img
-O
が出力形式を決めるためのオプションで、ここでbinary
を指定すると、生のバイナリデータに変換されて出力がされる。
出来上がったイメージファイルの内容を見てみると、以下のとおり:
$ hexdump -C hello-os.img 00000000 eb 4e 90 48 45 4c 4c 4f 49 50 4c 00 02 01 01 00 |.N.HELLOIPL.....| 00000010 02 e0 00 40 0b f0 09 00 12 00 02 00 00 00 00 00 |...@............| 00000020 40 0b 00 00 00 00 29 ff ff ff ff 48 45 4c 4c 4f |@.....)....HELLO| 00000030 2d 4f 53 20 20 20 46 41 54 31 32 20 20 20 00 00 |-OS FAT12 ..| 00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000050 b8 00 00 8e d0 bc 00 7c 8e d8 8e c0 be 74 7c 8a |.......|.....t|.| 00000060 04 83 c6 01 3c 00 74 09 b4 0e bb 0f 00 cd 10 eb |....<.t.........| 00000070 ee f4 eb fd 0a 0a 68 65 6c 6c 6f 2c 20 77 6f 72 |......hello, wor| 00000080 6c 64 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 |ld..............| 00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.| 00000200 f0 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00001400 f0 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00001410 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00168000
ちゃんと出来上がっているのが分かると思う。
Makefileの作成
これでとりあえずフロッピーディスクのイメージが出来たわけだけど、このコマンドを毎回打つのは面倒。
打ち間違いとかも怖いし。
(昔、ShellのTabによる補完でgcc -o hoge.c hoge.c
を実行してしまって、せっかく書いたソースを空にしてしまったことがある・・・)
そこで、簡単なMakefileも用意してみた:
.PHONY: all clean do all: hello-os.img hello-os.img: hello-os.o i386-elf-objcopy -O binary $< $@ hello-os.o: hello-os.s i386-elf-as -o $@ $< clean: -rm *.img *.o do: hello-os.img qemu-system-i386 -fda $<
実行するコマンドの前にあるのは必ずタブでないといけないので、そこだけは注意。
これで、make
とすれば、イメージが作成されるし、make do
とすれば、qemuが立ち上がって実行もされる。
今日はここまで!
- 作者: 川合秀実
- 出版社/メーカー: マイナビ出版
- 発売日: 2006/03/01
- メディア: Kindle版
- この商品を含むブログを見る