はりぼて日記
12月 26 (火曜日) 2006 | ||
08:32
|
六日目
|
|
六日目 〜3。 終了〜。
C言語で書かれたプログラムのソースは大抵いくつものファイルに分かれていますね。それはどういう理屈なのかってこと。 ここいらへんはだいたいOKかな? ツルっと読み終わりました。 |
||
12月 23 (土曜日) 2006 | ||
17:18
|
五日目4
|
|
五日目 9〜。
セグメンテーションか。えとえと??? これがややこしいんだよなぁ。元来は便利な機能なんだけど。P112の上のほう。 MOV AL,[DS:EBX] えーっと。この場合、[]内が示す番地のデータをALにコピーしろと。 で、「DS:EBX」と書かれている場合。32bitになっている現在は、DSレジスタがあらわすアドレス+EBXの値ってことでいいのかな? たとえばDSが 0x1000。EBXが0x0200だとすると、ALレジスタには0x1200番地の内容がコピーされるって理解でいいのかな。 えーっと。P112の真ん中らへん。わかんね〜なぁ・・・ まてよ? パレットとそっくりだと・・・ こういう意味なのかな?。「セグメントレジスタ」に設定するのは、セグメント番号。このセグメント番号っていうのは単なる番号。つまり、1番・2番・・・・8000番までありと。で、さらに、この1番や2番という番号(数値)はなんにもアドレスとかとは関係ない。単に「何番目か?」っていうだけ。じゃ、セグメントレジスタに、3を設定したとする。その場合、実際には何番地を読み込むのか?。 「いや〜。3番は0x0100からだよ。あと、4番は0x8000だよ」 って感じで、勝手に好きに設定できるっていう意味なのかな?? あ〜! わかった。そういうことか!!!。つまり、これは単なる表なんだ!。メモリのどこかに、ズラーっと8191個分の表を確保し、そこに実際の開始番地や大きさ等の情報を設定しておくと。なるほどねぇ。 そうなると、たとえばセグメントレジスタに4を設定する。そして0x0100番地を読み出そうとしたとする。その場合、CPUは本当のホントの0x0100番地を読むのではなく、GDT表の4番目を調べる。たとえばここに0x2000が設定されていれば、実際には0x2100番地が読み出されると。そんな感じかな?? たとえばだけど、メモリが1GBあるパソコンだとしよう。GDT表の一番目に、開始番地0x0000・大きさ512MBを設定し、二番目に開始番地0x8000・大きさ512MBを設定すると、このOSではセグメントが2個しか使えない!なんて理屈になると。(実際はシステムで使っている部分とかがあるからそんな単純じゃないんだろうけどね。理屈としてはこんな感じでそ?) なるほど。この感覚とほぼ同じ感じでIDTがあると。IDTも表って考えていいかな。こっちは「割り込み番号と実際に実行されるプログラムが書いてある番地」ってことね。 ここも、たとえばだけど、全てのIDTに0x5000って書いたとすると、キーボードだろうがマウスだろうがどんな割り込みが起こっても全て同じ動作をするなんていうおかしな状態にすることもできると。 なーるほどねぇ。つまり、GDT(セグメント設定用の表)と、IDT(割り込み時の実行プログラム位置の表)を設置しなくてはならない。で、この二つの表は、空いていれば好きな場所に設定できるわけですな?。 ・・・あれれ??? ここでとりあえず終了?? ほ・・・よかった〜。つーわけで、とりあえず五日目終了〜。 |
||
15:03
|
五日目3
|
|
五日目 〜8 まで終了〜。
ふむ! ここは幸いあまり難しくなかったなぁ。 (とはいっても例によってすこしあやしいんですけどね。(^^; ) ・・・嗚呼!それにしても、グラフィックがだんだん出来上がっていくのを見るとつらいなぁ・・・ フォントやマウスや画面デザインをいじりて〜! |
||
12月 22 (金曜日) 2006 | ||
17:24
|
五日目2
|
|
五日目 〜2。
うーむ。構造体そのものはそんなわけで解っている。structを使って定義し、HariMain内で宣言して使えるようにすると・・・ struct BOOTINFO *binfo; ・・・え”? *binfo? binfoじゃなくて? *? え〜???? ひええぇぇぇ!!! わっかんね〜!!(泣 ・ ・ ・ ・・・ぁ〜 あ〜 あぁ〜!なるほどそういうことか! 前後の読み込みが足りなかった。なるほど。これは、「俗にいう変数宣言」じゃないんだ。極論すれば、「メモリのアドレスに名前をつけて扱いやすくしたい」というだけのことなのか!。勘違いしてた。 ええと、まず、一個前のソースでやってるよね。つまり、 binfo_scrnx = (short *) 0x0ff4; とか。これはどういう意味かって言うと、書き方が特殊なので「あれれ?」と思ったけどなんのことはない。 「メモリ番地 0x0ff4〜0x0ff5(2バイト分)を、binfo_scrnxっていう名前でアクセスできるようにしてくれ」 ってだけのことじゃマイカ。例の「型キャスト&省略」タイプの書き方なのでわからんかった。キャストや省略を無視して書けば、 short *binfo_scrnx; binfo_scrnx = 0x0ff4; と、こうしているだけなんですなぁ。なるほどなるほど。 で!!!! 同じようなことを構造体で一まとめにしてやっちゃおうってわけね。なるほど〜。 ちょっと変則的だけど、私はこんなふうに理解してみた。 たとえば、 struct BOOTINFO binfo; と普通に「binfo構造体」を定義する。その場合、定義どおりに、あるどこかのメモリ番地にbinfo用のエリアが予約される。(これはたぶん、毎回不定のはず。)じゃ、たとえば解りやすく、0x1000に割り当てられたとしよう。そうすると、 0x1000 char cyls 0x1001 char leds 0x1002 char vmode 0x1003 char reserve 0x1004 shor scrnx 0x1005 〃 0x1006 shor scrny 0x1007 〃 0x1008 char *vram (ポインタすなわちメモリアドレス用なので4バイト) 0x1009 〃 0x1010 〃 0x1011 〃 っとまあ、こういう感じになるわけだ。 ・・・・・で!!!!! この、毎回ちがうアドレスに設定される binfo構造体の開始アドレスを、0x0ff0 に強制的に設定したいわけ。(0x0ff0〜12バイトの部分には、asmhead.nasによってグラフィック関係の値がすでにセットされているので)そのための方法が、 struct BOOTINFO binfo; じゃなくて、 struct BOOTINFO *binfo; binfo = 0x0ff0; になるわけだ!(例によって型キャストとかはちょっと省略してある)なるほどなるほど〜!!! シンプルに分解したら、やっと解ったぞ! |
||
16:13
|
五日目
|
|
五日目〜。
うは! しょっぱなからむずかしいなぁ。構造体かぁ。 ええと、構造体そのものは幸い解る。ようするにこれは、配列だ。 たとえば、一年間の気温を記録したいとする。1〜12までと、数は決まっている。また、記録するデータも全部気温で同じようなものだから、12個の変数全ての型は同じでよい。そういう場合に、 int month[11]; とかやれば、12個のint型変数を用意してもらえる。 データを格納する時も取り出す時も、 a[8] みたいにすればいい。 しかし、もし、使いたいデータがみんな型がバラバラな場合どうしたらいいだろう? たとえば、「生徒の特徴」とか。 人の特徴だから、配列内に収めるデータは型がバラバラになる。 生徒「よしお君」 ┬─ 身長(int型) ├─ 体重(int型) ├─ 出身地(char型) └─ 年齢(Doble型) C言語では、変数は宣言時に型を決める。なので、上記のような場合、当然 int yoshio[3] ; とかやっちゃうと、出身地や年齢を格納できなくなってしまう。 int yoshio[3], ただし[2]はchar型,[3]だけSoble型; こんなことはできないだろうか? ま、それこそが構造体ということになるわけ。 構造体はさらに、こんな便利な要素もある。各変数を[2]とか[3]じゃなく、名前をつけて管理できる。これなら、「あれ? ええと、体重って[1]だっけ?いや、[2]だったっけ?」なんてことが起きないようになると。つまり、上記のような配列を作りたい場合、 struct 生徒データ { int 身長; int 体重; char 出身地; Double 年齢; } なんて宣言しておくと、「生徒データ」型の変数の配列を新しく定義できるわけ。「新しい変数型の定義」だから、以降は int a; int型の a という変数を宣言 char b; char型の b という変数の宣言 struct 生徒データ 義男; 生徒データ型の 義男 という変数を宣言 って感じで使えるようになると。こういうわけ。 配列内部へのアクセスも、普通の配列だと int a[11]; 配列の宣言 a[0] = 12; 一月の気温をセット a[1] = 14; 二月の気温をセット と、こういう感じになるけど、構造体の場合は struct 生徒データ 義男; 構造体「義男」を宣言 義男.身長 = 153; 義男の身長をセット 義男.体重 = 43; 義男の体重をセット と、こういう感じでできるようになるわけです。 (一応念のため書いとくけど、変数名等には実際は日本語は使えません) |
||
06:33
|
四日目3
|
|
四日目 終了〜。
やっべぇ!「OSっぽい」画面だ! う〜。いじりてー! まてまてまて。ここはグっと我慢。まだ先は長いんだから(汗 さて、この四日目で一番私が大事だと感じたのが、例の「アセンブラでCの関数を作っちゃう!」ってこと。 実は以前、私はOSの実験と学習のためにアセンブラで小さなブートプログラム(hideyOS 0.1)なんてのを作っていたことがあります。だんだん規模が大きくなってきて最後は収集がつかなくなって放置になってしまったのですが。 で、これに取り掛かる前、GCC(MinGW)でいろいろいじくっていた時のこと。どうしてもキーボードからの信号を受け取る方法がわからず、「こりゃ、アセンブラでやらないといけない部分だな」と判断して、GCC内でアセンブラを扱える「インライン アセンブラ」という機能を使おうとしたんです。 ・・・挫折・・・ いや、単に私の英語力や理解力が低いだけなんでしょうが、いくら調べても「チョコチョコ! パッ!」っとできる例や説明が見つからなかったんです。 当時の私は、「だめだ!インラインアセンブラは高機能なぶん、猛烈に複雑でかえってわからない!」と感じました。 その証拠に、その後、naskで書き始めたら数週間で目的を達成できたのです。(アセンブラそのものも勉強しながらプログラムしてた) しかし、やっぱりアセンブラ。プログラムしていくうち、漠然とではありますが、どんどん「・・・この調子じゃ、俺の頭が追いつかない・・・」になって来ました。 「naskでCの関数が作れたらなぁ・・・」 当時、そう思ったものです。 この四日目では、そのための方法と実例がばっちり書かれています。これを応用すればいろいろなことができるはず。 なんだか楽しみになってきました。 |
||
05:46
|
四日目2
|
|
四日目 〜5 まで終了〜。
うむむ・・・。ここがうわさのポインタ部分か。さらっと読むつもりだったけど、つい何回か読み直してしまった。 正直、ちょっと私の現在の理解はあやしいなぁ。でもとりあえず良しとしておくか。(進まないから) 現在の私の理解(まちがってたりたりなかったりの可能性大) ・メモリに直接値を書く必要がないなら、ポインタなんていらない! ・たぶん、ほとんどの普通のプログラムはポインタなんか使わなくても書ける。 ・OSなので、メモリに直接アクセスする必要がある。 ・Kタンがnaskfunkで作ったような関数があればポインタなんていらない ・しかしC言語ではそんな関数はない ・なので、ポインタというものを使う ・・・と、こんな感じ。で、さらに、 ●たとえばC言語に、<< アドレス番地 >> なんて命令があれば、*pなんてわけわからない書き方せんでもいい。 あるメモリに12を代入したいとする。(じゃ、たとえば0032番地とする。 アセンブラなら、 MOV BYTE[0x0032],12 私の「妄想C言語」なら、 <<0x0032>> = 12; で、実際のC言語の場合なら、 char *p; p = 0x0032; *p = 12; こう書かなくてはいけないと。そういうことみたいだな。キャストや演算( *(p+1)とかそういうの )は、便利に使うため。一旦忘れる!ってのが、理解を深めるのに役立ちそうかも?? ま、とりあえずこのくらいにしておこうっと。(こりゃ、早くも二順三順決定っぽいなぁ(^^; ) |
||
12月 21 (木曜日) 2006 | ||
00:21
|
四日目
|
|
四日目〜。
・・・その前に。先の三日目で疑問に思ったこと。(この本のことだからきっと後で出てくるのかもしれないので、この段階では無理に調べない。でも忘れちゃいそうなのでメモ。) ?? 16bitから32bitにスイッチされた場合、メモリの内容はそのままなのか ?? たぶんそうだろうとは思うけど、なにか変化や保障されない部分はないのか?? ・・・と、こんなこと。 さて、四日目だけど、一番最初ですこーし躓いた。69P〜70Pの、_write_mem8に関する部分。 一番目のもの: [ESP+4] 二番目のもの: [ESP+8] 三番目のもの: [ESP+12] 四番目のもの: [ESP+16] ??? あれ?これどういう意味かな??? あー。なるほど。そうかそうか! つまり、naskfuncみたいに「アセンブラでC言語から使える関数を作った場合」に、関数のパラメータの値が順番に格納されるわけね。パターンとして。 たとえば、私が hideyosi(int one,int two int three); こういう関数を考えてC言語側で定義したとする。パラメータは三つ。で、この関数を実際に使おうとして、Cのプログラムから sss = hideyosi( 1 , 2 , 3); と、こんなふうにコールしたとする。その場合に、 [ESP+4]、つまり(ESPの値+4)番地のメモリに、1が [ESP+8]、(ESPの値+8)番地のメモリに、2が [ESP+12]、(ESPの値+12)番地のメモリに、3が セットされると、そういう意味かぁ。なるほどなるほど。 |
||
12月 19 (火曜日) 2006 | ||
00:59
|
三日目2
|
|
8〜10読破。三日目終了〜。
・・・ぶっちゃけ、ここいらへん、ちょーっと理解が甘いと自覚しとります。でも、私は細かい実務より理屈理解を優先するタイプなので、あえてここで無理に立ち止まらないで進んじゃおうと。(あとで読み返せばいいわけだし) とはいっても、流し読みってわけじゃないですよ。 このセクションで大事なのは、まず、32bitとはなんじゃらほいということ。あまり詳しくない人(Kタンに教えてもらう前のオイラ)にとっては、多ビット=高性能 という、単純な図式しか頭にないことが多いですよね。もちろんこれは別にまちがいではないのですが、なぜ32bitは高性能なのか・逆になぜ16bitは低性能なのか・どうしていまや32bitや64bitが廉価で当たり前な時代に16bitを勉強しなくてはいけないのか。そこいらへんを怪しく理解している場合が多いんですよね。(え”私だけ??) このへんのことは、私も昔自習してみたことがあります。ここいらへん。ご参考までに。 それともうひとつ大事なこと。この本では、「最後は機械語になる」と書かれていますが、私はあえて、一段緩和したいと考えています。つまり、「とにかくなに言語でもいいから.obj形式まで持って来い!」っていうこと。objにさえできれば、それを作ったのがC言語だろうがC++だろうがJAVAだろうがどうでもいい。できあがったobjファイルを連結すれば、それでプログラムになると。 この感覚(とりあえず感覚だけでも)を持っていれば、アセンブラが向いていればアセンブラを使えばいいし、Cが向いていればCを使えばいい。適材適所で使い分ければいいということになります。このセクションは、それをとりあえず提示and実践しているわけですよね。これが大事なことだと感じました。 (おおげさ?? (^^; ) |
||
12月 16 (土曜日) 2006 | ||
18:09
|
三日目
|
|
さて三日目〜。まずは[7]まで。
IPLの作成なんだけど、ここすっごく重要な部分で、かつ、どうでもいい部分なんですよねぇ。(え?矛盾してる??) どういうことかと言うと、かつてOSを自作したいという人達はほとんどここに達することなく終わってしまっているんです。つまり、OSの本体をメモリにロードして実行する。こういう動作をできるようになるまでがすごく高いハードルだったんですよね。 でも、逆に言えば、これはOSでもなんでもない作業ですよね?。大事なのはこれ以降の、OSの本体の部分なんです。なので「ほんとうはどうでもいい部分」ということになるんです。 川合さんもずいぶん「その部分はどうでもいい部分なんだから、在来のものや汎用のプログラムを有効活用して、OS本体のプログラムに着手しよう」と言い続けてましたね。 |
||
« 3 4 5 6 7 8 9 10 11 12 (13) 14 »  |
PopnupBlog V3 Denali created by Bluemoon inc. |