- 作者: 川合秀実
- 出版社/メーカー: 毎日コミュニケーションズ
- 発売日: 2006/03/01
- メディア: 単行本
- 購入: 36人 クリック: 735回
- この商品を含むブログ (299件) を見る
C言語でアプリケーションを作る会。どっちにしろ、hrb2bim などの独自ツールは使用していないため、C言語で開発するときもリンカスクリプトを利用しているので特に問題なかった。
途中でどうしても正しく動作しなかったのでかなりてこづったが、最終的には動作させることが出来るようになった。
一つのポイントは、gccでコンパイルするときに調子になって-O3
を挿入していたのだが、これはやってはいけない。
--- a/program/haribote-os/day15/haribote-000/Makefile +++ b/program/haribote-os/day15/haribote-000/Makefile @@ -33,7 +33,7 @@ $(TARGET).img: ipl10.bin $(TARGET).sys %.o:%.c - gcc -m32 -O3 -c -fno-pic -nostdlib -fno-builtin -o $@ $< + gcc -m32 -c -fno-pic -nostdlib -fno-builtin -o $@ $< objdump -D $@ > $@.dmp
あとは、StackをオーバフローさせるアプリケーションがQEMU上では動作しない。 QEMUのバグだと思われるが、それ以上は追求しなかった。
次に、ウィンドウを起動させた。これもAPIの実装を間違えていたので最初動かなくてかなり戸惑ったが、修正して動作するようになった。
APIの構造が少し難しくて挫折しそうになっているのだが、まずはPUSHAD
という命令。これは以下と等価らしい。
PUSH EAX PUSH ECX PUSH EDX PUSH EBX PUSH ESP PUSH EBP PUSH ESI PUSH EDI
例えば、winhelo2.c
で以下のようなコードを記述した場合。APIへの呼び出しはどのようになるのだろうか。
winhelo2.c
#include "a_nask.h" #include "sprintf.h" char buf[150 * 50]; void HariMain (void) { int win; win = api_openwin (buf, 150, 50, -1, "hello2"); api_boxfilwin (win, 8, 36, 141, 43, 3 /* yellow */); api_putstrwin (win, 28, 28, 0 /* black */, 12, "hello, world"); api_end (); }
まずは、api_openwin()
が呼ばれるのだが、これはアセンブリで実装されておりAPIを実行させるための割り込みを発行させるだけである。
int 0x40
で呼び出されるのは、割り込みルーチンとして登録されている‘asm_hrb_api→
hrb_api`である。
a_nask.nas
api_openwin: ; int api_openwin (char *buf, int xsiz, int ysiz, int col_inv, char *title); push edi push esi push ebx mov edx, 5 mov ebx, [esp+16] ; buf mov esi, [esp+20] ; xsiz mov edi, [esp+24] ; ysiz mov eax, [esp+28] ; col_inv mov ecx, [esp+32] ; title int 0x40 pop ebx pop esi pop edi ret
asm_hrb_api
(naskfunc.nas)
asm_hrb_api: sti push ds push es pushad pushad mov ax,ss mov ds,ax mov es,ax call hrb_api cmp eax,0 jne asm_end_app add esp,32 popad pop es pop ds iretd
hrb_api
(console.c)
int *hrb_api (int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax) ...
最初のPUSHADはスタック退避、2番目のPUSHADはhrb_api
に引数を渡すため。hrb_api
内でレジスタを書き換えるために、以下のようなコードが入っている。
console.c
int *reg = &eax + 1; } else if (edx == 5) { ... reg[7] = (int)sht;
これにより、退避したスタックの先頭にsht
の値が入ってくる仕組みだ。
この辺が難しいので一応まとめた。正しいかどうかは不明だが。 横軸方向にプログラムが流れていく。スタックに複数の値を退避しながら、生成したshtをどうやって戻しているのかを見て欲しい。