3

まあ、正確ではありません。機能的なデータ構造についてもっと質問があります。

CPU の実行をモデル化するとします。CPUの状態を変更する命令のセット(スタックベースのCPUだとします。ジャンプだけにオペランドがあります...など)、プログラムを構成する命令のリスト、およびラベルがあります。ジャンプは、オフセットではなく、ラベルへの参照によって行われます。これをどのように表現すればよいですか?

のようなプログラムがある場合[Label "foo", Add, Add, Mult, Label "bar", Jnz "foo"]、 をヒットJnz "foo"するまでに、ラベル「foo」を前後に検索して実行を続行する必要があります。それは少しばかげているようです。ラベルへの素早いジャンプを可能にする、より優れたデータ構造を持つことができるはずだと思います。ここで、オフセットを保存したくないと勝手に言​​います。CPUが自己変更コードなどを許可しているとします。参照が現在のバージョンのコードを指していることを確認しながら、コードにパッチを適用するにはどうすればよいですか?

私はジッパーのアイデアが好きです。O(1)時間で定義済みの場所にジッパーをジャンプさせるという考えが理にかなっているのかどうかはわかりません

4

2 に答える 2

2

答えは(しかし、それがあなたが望むものかどうかはわかりません)LLVMが行うことを行い、コードをBasicBlocksとして保存することです。このシステムでは、各ブロックは最初からしか入力できないコードです。最後の命令は、別のブロックへのジャンプでなければなりません。次に、命令のリストにある代わりに、ラベルが基本ブロックに付けられます。プログラムは次のようになります。

newtype Lable = [Char]
data Code = Data.Map Label [Instruction]

ジャンプの指示を出すとlookup、マップ内のそのブロックを単純にブロックして進み続けます。

これは、コードを最適化することが目的である場合 (これも LLVM が使用する理由) にはいくつかの利点がありますが、単にコードを命令のリストとして表現するというパターンを崩してしまいます。

一方、プログラム コードにラベルが含まれている CPU やコンピューティング モデルは思い浮かびません。アセンブリでは、コードの次の行の固定オフセットを記述する便利な方法にすぎません。それらは最終的に出力に含まれず、コードが実行時に変更可能な場合は、jmp命令も変更する必要があります。

于 2013-05-29T16:15:45.917 に答える
1

私は次のようなものを提案します

import Data.Map as M
data Code = Code { instructions :: [Instruction], labels :: M.Map String [Instruction] }

ここで、ラベル マップの値は指示リストと共有されます。ラベルを命令ストリームに保持して、次のようなことを行うことができます

mkCode is = Code is (scan is)
              where scan [] = M.empty
                    scan (Label l:js) = M.insert l js (scan js)
                    scan (_:js) = (scan js)

適切なコード値を構築します。

Data.Map二分探索木を実装することに注意してください。ハッシュ テーブルが必要な場合は、Data.Hashtable.

于 2013-05-29T02:07:14.880 に答える