-
hoehoe1234
- 439
- 1
- 0
- 0
![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
エンジョイC050回目CSVの解析とJSR(2021-04-11) エンジョイC、記念すべき第50回目の講座となりました。最近はC言語をほったらかして延々とアルゴリズムとOSコードリーディングをやっております。しかし、人が増えない!ということで計画発動です。 pic.twitter.com/jlpTC2o20s
2021-04-15 19:18:09![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
OSコードリーディングに興味のある人もおおいのではないでしょうか?しかし、現実的に読み進められる人はごく僅かです。しかし、「教えてもらえばよめるのではないか?」との仮説で始めたこの講座、たしかに読めるようにはなるのですがやはりとっつきにくい。とうことで検討開始です。
2021-04-15 19:21:14![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
興味をもってもらえることを前提に、すくなくとも ①CPUとレジスタ ②C言語 ③関数の呼び出し はわかないと何をやっているのかまったくわからないのでは?となり、GWにOSコードリーディングブートキャンプを開催することになりました。
2021-04-15 19:22:35![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
実際、OSのコードリーディングはむずかしいのですが、前提条件としてかなり低い分野となります。なにより ①数学的な背景が不要(中学程度) ②高度なアルゴリズムが不要 ③FWもライブラリもなくひたすらC言語+アセンブラ となっています。数学が不要なのは大きいですね。
2021-04-15 19:25:02![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
OSコードリーディングの目標は唯一です。それは「読み切って理解すること」です。それにどのような付加価値をつけるかは参加されている生徒さんそれぞれでよいと思います。私にとっては書籍執筆のネタにもなりますし、「カーネルコードを読み切る」という自分への挑戦にもなっています。
2021-04-15 19:26:51![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
4日間、50時間で計画していたのですがさすがにそれはちょっと大変なので3日間、30時間の計画としました。1日8時間で組んでいますがたぶん1日10時間の3日間になるとおもいます。後日計画を配布しますのでみなさん、ぜひブートキャンプにご参加ください。
2021-04-15 19:28:21![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
前回の思い出しとしてJSR命令の整理をします。形式は ①JSR reg, dest です。regはレジスタ、destはジャンプ先となります。unixで使用されているのは実質的に ②JSR PC, dest か ③JSR R5, dest になります。R5はいわゆるBP(ベースポインタ)です。 pic.twitter.com/hsgWBNX39J
2021-04-15 19:34:11![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
JSRはサブルーチンを呼び出す命令(アセンブラ)です。まずはpdp11-40ブックを読んでJSRの「挙動」について理解します。黄色マーカの部分が挙動ですね。 pic.twitter.com/kgHMaA29fi
2021-04-15 19:38:08![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
こいうのを読んで、理解することがやはりOSコードディリングの敷居を高くしているように感じます。実際にやってみると難しくないのですが「とっつきにくさ」はありますね。これをわかりやすく説明するために塾があるのですね。
2021-04-15 19:39:35![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
日本語に意訳すると ①内部レジスタ(tmp)にジャンプ(dst)先を保存 ②スタックにレジスタ(reg)をプッシュ(↓があるのでスタックは1つ伸びる) ③レジスタにPCを代入(この時点のPCはJSR命令の次の命令を指している) ④PCにtmpを代入する となります。これが「挙動」の説明です。
2021-04-15 19:42:42![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
「挙動」を追うだけでもスタックの解析はできますがストレスがたまります。なぜでしょう?それは「意味(意図)」として言語化されていないからです。言語化されていないと毎回毎回この操作をなぞる必要があります。これがストレスになるのです。これはあまり望ましくないですね。
2021-04-15 19:44:19![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
本日の講義の解説をする前に、この動きの「意味」を考えてみましょう。形式は ①JSR PC, callee と ②JSR R5, callee とします。C言語から関数を呼び出す場合は①の形式が利用されます。②の形式はアセンブラから使用することになります。
2021-04-15 19:46:02![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
これは本文にも説明がありますが、意味的にはサブルーチンにジャンプするのは自明として、レジスタの動きを言語化します。次のようになります。 ①使用するレジスタ(reg)をスタックにプッシュする ②regにその時点のPC、すなわち「戻りアドレス」を代入する。 ③指定されたdstをPCにセットする。
2021-04-16 02:27:05![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
となります。大切なのは①と②ですね。要は「指定されたレジスタを保管のためにスタックにプッシュして戻りアドレスはそのレジスタに格納する」となります。違う言い方だと「戻りアドレスを設定するレジスタはスタックに保管しておく」となります。なのでこれがリンケージレジスタと言われます。
2021-04-16 02:28:32![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
JSR R5, destの場合はこの通りの動きとなります。他の汎用レジスタでも同じですね。ただし、JSR PC, destとした場合にだけ動きの意味が異なります。PCは実行している場所そのものですので保存されるのもPC、dstが代入されるのもPCとなります。
2021-04-16 02:36:34![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
手順に従い ①まずPCがスタックにpushされます(これはJSRの次の命令、すなわち戻りアドレスです) ②PCにPCがロードされます ③PCにdstがロードされます 2番めの処理は3番めの処理で上書きされるんですね。ですからdstに移動したときには環境ポインタであるBPは「セーブされていません」。
2021-04-16 02:38:45![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
これがC言語規約による呼び出しで、関数の頭で push BP mov SP BP が行われる理由です。JSR R5, dstの場合はR5(BP)を保存する必要はありませんね。unixではこの違いをうまく利用してレジスタをスタックに保存しています。それがcsv関数となります。
2021-04-16 02:41:03![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
ここからは『はじめてのOSコードリーディング』(以下黒本)のcaller/calleeの解説となります。この2つの関数は見ての通りの関数です。 pic.twitter.com/9DDYx3qSIX
2021-04-16 02:45:38![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
caller/calleeのコンパイルされたコード(アセンブラ)となります。エミュレータでコンパイルした結果だそうですがすごいですね。当塾にはそのような環境はないのでとても参考になります。実際、コメンタリだけでは解析は難しく、黒本がなければかなりコードリーディングは難航していたと思います。
2021-04-16 02:48:31![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
Unix V6のコードは ①Lionsコメンタリ ②はじめてのOSコードリーディング ③pdp11-40 processor handbook と、追加で④souce_with_linno_v6があれば読み解いていくことができると思います。皆さんもご興味あればぜひ購入してみてください。③と④はネットで公開されていますのでダウンロードできます。
2021-04-16 02:51:55![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
callerがcalleeを呼び出す箇所はここになります。pdp11のC言語では関数呼び出しにJSR PC形式を使っていることが分かります。 pic.twitter.com/EIlbPOyDUL
2021-04-16 02:55:54![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
calleeの先頭に制御が移った時のレジスタとスタックの内容です。 BP 変更なし SP 1ワード減る(下位に) PC calleeの先頭アドレス スタック 図の通り。戻りアドレスはアセンブラコードでいうと31行になります(JSRの次の行)。 pic.twitter.com/I7Jncvycch
2021-04-16 02:59:15![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
図黄色がcallerから積み上げていったスタック、左水色が黄色からの続き(上に続くイメージ)です。「CSVがなにをやっているか?」というと「R2~R4」のレジスタのセーブなんですね。C言語側でローカル変数にレジスタ変数を使うためだと思われます。 pic.twitter.com/fUN3B93aG6
2021-04-16 03:13:48![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
詳細は書けませんが、この関数(csv)は、コンパイラにより挿入(されるらしい)され、関数の最初で呼び出されます。ここでJSR R5, csv形式が使用されています。 pic.twitter.com/U0X9cAXr1K
2021-04-16 03:18:53![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)
CSVのコードはこちらとなります。JSR R5形式で呼ばれたにもかかわらず、CSVから戻るときにはなんとJSR PC形式を使用しています。これで何が起こるか?ということです。 pic.twitter.com/l7iPBBqIZq
2021-04-16 03:20:52![](https://tgfile.tg-static.com/static/web/img/placeholder.gif)