Ubuntu 18.04.1 LTSでやる 30日OS本 〜22日目〜

Ubuntu 18.04.1 LTSでやる 30日OS本、22日目です。 他の章へのリンクはここにあります。

1. OSを守ろう

問題なく動作していることが確認できました。

2. バグ発見を手伝おう

QEMUでもbug1.hrbでは「AB」と表示された後に例外が発生しました。EIPレジスタの値を表示させると「EIP = 00000062」となりました。 bug1.mapを見ると、

(前略)
.text           0x0000000000000030       0x73
 *(.text)
 .text          0x0000000000000030       0x5d obj/bug1.o
                0x0000000000000030                app_main
 *fill*         0x000000000000008d        0x3 
 .text          0x0000000000000090       0x13 obj/a_nasm.o
                0x0000000000000090                api_putchar
                0x000000000000009c                api_end
(後略)

となっており、app_main内で例外が発生したことがわかります。 bug1.lstの生成方法がわからなかったので、詳細はbug1.oをディスアセンブルすることで確認します。 objdump -M intel -D obj/bug1.oの結果の一部を下に示します。

00000000 <app_main>:
   0:   55                      push   ebp
   1:   89 e5                   mov    ebp,esp
(中略)
  2f:   83 c4 10                add    esp,0x10
  32:   c6 45 0f 43             mov    BYTE PTR [ebp+0xf],0x43
  36:   8a 45 0f                mov    al,BYTE PTR [ebp+0xf]

この結果と 0x30 + 0x32 = 0x62 より、mov BYTE PTR [ebp+0xf],0x43で例外が発生していたと特定できました。 なお、'C'=0x43です。

ところで割り込みの処理asm_inthndlerXXは大体どれも同じ処理をしています。同じことを繰り返し書いておくのは嫌なので、NASMのマクロを利用してまとめてしまいました。 NASMのマクロは

%macro [マクロ名] [引数の数]
(中身)
%endmacro

という形で宣言でき、

[マクロ名] [引数1],[引数2],...,[引数n]

で呼び出せます。マクロの中身にある%1, %2, ..., %nが対応する番号の引数として展開されます。

3. アプリの強制終了

アプリの実行途中で強制終了できるようになりました。[Shift]+[F1]ではなく[Break]で強制終了するようにしようとも思ったのですが、 [Break]は送られてくるキーコードが長くて面倒だったため、今後の課題とすることにしました。

4.・5. C言語で文字列表示

ここでの説明でリンカスクリプトの中身が解読できます。ESPレジスタの初期値がここでは0x400となっているので.head内を書き換え、 下の方にある.dataから始まる部分を.data 0x400: ~~~に変更します。https://vanya.jp.net/os/haribote.html#gcchrbにあるリンカスクリプトの アプリケーション用と同様のものに差し替えても良いかも知れません。

ここからAPIを利用して何かをすることが増えるので、api_***という関数の宣言を書き並べたヘッダファイルapi.hを作っておくことにしました。 また、"Hari"が見つからないと実行されないようになったため、アセンブラでアプリを作る場合にも一旦オブジェクトファイルを作ってリンクするという流れにします。 Makefileをこれらに合わせて変更します。

APPS := $(patsubst app/%.c,bin/%.hrb,$(patsubst app/%.asm,bin/%.hrb,$(filter-out app/api.asm app/har.lds app/api.h,$(wildcard app/*.*))))
# あるいは
#APPS := $(patsubst app/%.asm,bin/%.hrb,$(filter-out app/api.asm,$(wildcard app/*.asm))) $(patsubst app/%.c,bin/%.hrb,$(wildcard app/*.c))

bin/%.hrb: app/%.c app/api.h obj/api.o app/har.lds Makefile
    gcc -fno-pie -march=i486 -m32 -masm=intel -nostdlib -c $< -o obj/$(*F).o
    ld -o $@ obj/$(*F).o obj/api.o -e app_main -Map lst/$(*F).map -m elf_i386 -T app/har.lds

bin/%.hrb: app/%.asm obj/api.o app/har.lds Makefile
    nasm -felf $< -o obj/$(*F).o -l lst/$(*F).lst
    ld -o $@ obj/$(*F).o obj/api.o -e app_main -Map lst/$(*F).map -m elf_i386 -T app/har.lds

obj/api.o: app/api.asm Makefile
    nasm -felf app/api.asm -o obj/api.o

として、$(APPS)をイメージファイルの依存関係に書いておけば良いです。なお、エントリポイントは「Harimain」 から「app_main」に変更してあります。api.asmは本でのa_nask_nasにあたるファイルです。 このようにしておけば、新しいアプリを作るときにもMakefileはいじらなくても良くなるはずです。多分。

6.・7.

ウィンドウが増えました。(書いていないので当然)出てきたウィンドウはまだ動かせません。