またまた間が空いてしまったけど、前回の続き。
今回はアドレスの問題を解決していく。
逆アセンブル
おさらいで、何が問題だったかというと、ブートセクタはBIOSによってメモリの0x7c00に読み込まれるのだけど、このコードだと先頭が0x0000だと思ってリンクが解決されてしまうので、正しく動作しないということ。
とはいえ、実際にどのようになっているのか分からないので、まずは逆アセンブルして確認を。
逆アセンブルには、objdumpを使えばいい。
これもBinutilsに入っているツール。
-d
オプションをつけると、逆アセンブルをしてくれる。
$ i386-elf-objdump -d hello-os.o
この結果は、以下のとおり:
hello-os.o: file format elf32-i386 Disassembly of section .text: 00000000 <pbr>: 0: eb 4e jmp 50 <entry> 2: 90 nop // 省略 00000050 <entry>: 50: b8 00 00 8e d0 mov $0xd08e0000,%eax 55: bc 00 7c 8e d8 mov $0xd88e7c00,%esp 5a: 8e c0 mov %eax,%es 5c: be .byte 0xbe 5d: 74 00 je 5f <putloop> 0000005f <putloop>: 5f: 8a 04 83 mov (%ebx,%eax,4),%al 62: c6 01 3c movb $0x3c,(%ecx) 65: 00 74 09 b4 add %dh,-0x4c(%ecx,%ecx,1) 69: 0e push %cs 6a: bb 0f 00 cd 10 mov $0x10cd000f,%ebx 6f: eb ee jmp 5f <putloop> 00000071 <fin>: 71: f4 hlt 72: eb fd jmp 71 <fin> 00000074 <message>: // 以下略
ただ、ちょっとおかしいのに気づくかもしれない。
例えば、0x50を見てみると、直値0xd08e0000をレジスタeaxに代入している。
ここはホントは、0x00をレジスタaxに代入すると出て欲しいところ。
それに、0x5cを見てみると、命令があるはずなのになぜかデータが出てしまっている。
これはなぜかというと、32ビットモード(プロテクトモード)で逆アセンブルされてしまっているから。
前回書いたとおり、ここは.code16
擬似命令を使って16ビットモード(リアルモード)の出力をしているので、逆アセンブルも16ビットモードで行ってやらないと、正しくならない。
16ビットモードであることを指定するには、-M addr16,data16
オプションを追加する:
$ i386-elf-objdump -d -M addr16,data16 hello-os.o
すると、以下のような出力になる:
hello-os.o: file format elf32-i386 Disassembly of section .text: 00000000 <pbr>: 0: eb 4e jmp 50 <entry> 2: 90 nop // 省略 00000050 <entry>: 50: b8 00 00 mov $0x0,%ax 53: 8e d0 mov %ax,%ss 55: bc 00 7c mov $0x7c00,%sp 58: 8e d8 mov %ax,%ds 5a: 8e c0 mov %ax,%es 5c: be 74 00 mov $0x74,%si 0000005f <putloop>: 5f: 8a 04 mov (%si),%al 61: 83 c6 01 add $0x1,%si 64: 3c 00 cmp $0x0,%al 66: 74 09 je 71 <fin> 68: b4 0e mov $0xe,%ah 6a: bb 0f 00 mov $0xf,%bx 6d: cd 10 int $0x10 6f: eb ee jmp 5f <putloop> 00000071 <fin>: 71: f4 hlt 72: eb fd jmp 71 <fin> 00000074 <message>: // 以下略
このとおり、ちゃんと16ビットモードで逆アセンブルがされるようになる。
アドレスの確認
さて、注目したいのは、0x5cの部分:
5c: be 74 00 mov $0x74,%si
もともとのコードは、次のようになっていた:
mov $message, %si
つまり、messageのアドレスをsiレジスタに代入していたわけだけど、messageのアドレスが0x74として解決されてしまっている。
このファイルだけ見れば、それは正しそうに思えるんだけど、実際にはこのファイルの先頭が0x7c00にロードされるので、messageのアドレスは、0x7c00 + 0x74 = 0x7c74でないといけない。
なので、このままでは正しく動作しない。
(messageが置かれている0x7c74ではなく、何が置かれているか分からない0x74のデータを読み込んで出力しようとする)
リンカとリンカスクリプト
ということで、このセクションが0x7c00にロードされて動作することを伝え、正しくアドレスの解決を行わないといけない。
そこで必要になるのが、リンカとリンカスクリプト。
リンカは、各オブジェクトファイルのセクションをまとめ、それが動作するアドレスにもとづいてアドレスの解決を行ってくれる。
そのとき、どのセクションをどのアドレスにロードし動作させるか記述するのがリンカスクリプト。
今回の場合、このセクションは0x7c00にロードされ、そのまま動作するので、そのようなリンカスクリプトを書いてリンクを行えばいい。
ということで、以下のような簡単なリンカスクリプトhello-os.ldscriptを用意した:
SECTIONS { .text 0x7c00 : { *(.text) } }
このリンカスクリプトを使うようにリンカ(ld、これもBinutilsに入っている)に指示してリンクを行うには、以下のようにすればいい:
$ i386-elf-ld -o hello-os.elf -T hello-os.ldscript hello-os.o
こうして出来たELFファイルを逆アセンブルしてみると、以下のような感じ:
hello-os.elf: file format elf32-i386 Disassembly of section .text: 00007c00 <pbr>: 7c00: eb 4e jmp 7c50 <entry> 7c02: 90 nop // 省略 00007c50 <entry>: 7c50: b8 00 00 mov $0x0,%ax 7c53: 8e d0 mov %ax,%ss 7c55: bc 00 7c mov $0x7c00,%sp 7c58: 8e d8 mov %ax,%ds 7c5a: 8e c0 mov %ax,%es 7c5c: be 74 7c mov $0x7c74,%si 00007c5f <putloop>: 7c5f: 8a 04 mov (%si),%al 7c61: 83 c6 01 add $0x1,%si 7c64: 3c 00 cmp $0x0,%al 7c66: 74 09 je 7c71 <fin> 7c68: b4 0e mov $0xe,%ah 7c6a: bb 0f 00 mov $0xf,%bx 7c6d: cd 10 int $0x10 7c6f: eb ee jmp 7c5f <putloop> 00007c71 <fin>: 7c71: f4 hlt 7c72: eb fd jmp 7c71 <fin> 00007c74 <message>: // 以下略
ちゃんと正しくアドレスが解決されているのが分かると思う。
ちなみに、このELFファイルをobjcopyでバイナリファイルに変換した場合、どう出力されるのか気になるところだけど、objcopyはロードされるアドレスの一番先頭をファイルの先頭として出力してくれるようなので、ちゃんと期待したバイナリファイルになってくれる。
Makefileの修正
最後の仕上げで、以前書いたMakefileを修正して、リンクも行うように。
.PHONY: all clean do all: hello-os.img hello-os.img: hello-os.elf i386-elf-objcopy -O binary $< $@ hello-os.elf: hello-os.ldscript hello-os.elf: hello-os.o i386-elf-ld -o $@ -T hello-os.ldscript $< hello-os.o: hello-os.s i386-elf-as -o $@ $< clean: -rm *.img *.elf *.o do: hello-os.img qemu-system-i386 -fda $<
これでmake
を実行したときに、リンクを行ってELFファイルを作成し、そこからフロッピーディスクのイメージを作成するようになる。
今日はここまで!
- 作者: 川合秀実
- 出版社/メーカー: 毎日コミュニケーションズ
- 発売日: 2006/03/01
- メディア: 単行本
- 購入: 36人 クリック: 735回
- この商品を含むブログ (299件) を見る