Skip to content

Instantly share code, notes, and snippets.

@kekyo
Created January 21, 2023 02:21
Show Gist options
  • Save kekyo/b8044942e63713c3fc7dfaf29b40518e to your computer and use it in GitHub Desktop.
Save kekyo/b8044942e63713c3fc7dfaf29b40518e to your computer and use it in GitHub Desktop.
ecma335-iii.1.7

III.1.7 Restrictions on CIL code sequences

As well as detailed restrictions on CIL code sequences to ensure:

  • Correct CIL
  • Verifiable CIL

There are a few further restrictions, imposed to make it easier to construct a simple CIL-tonative-code compiler. This subclause specifies the general restrictions that apply in addition to this listed for individual instructions.

III.1.7.1 The instruction stream

The implementation of a method is provided by a contiguous block of CIL instructions, encoded as specified below. The address of the instruction block for a method as well as its length is specified in the file format (see Partition II, CIL Physical Layout). The first instruction is at the first byte (lowest address) of the instruction block.

Instructions are variable in size. The size of each instruction can be determined (decoded) from the content of the instruction bytes themselves. The size of and ordering of the bytes within an instruction is specified by each instruction definition. Instructions follow each other without padding in a stream of bytes that is both alignment and byte-order insensitive.

Each instruction occupies an exact number of bytes, and until the end of the instruction block, the next instruction begins immediately at the next byte. It is invalid for the instruction block (as specified by the block’s length) to end without forming a complete last instruction.

Instruction prefixes extend the length of an instruction without introducing a new instruction; an instruction having one or more prefixes introduces only one instruction that begins at the first byte of the first instruction prefix.

Note: Until the end of the instruction block, the instruction following any control transfer instruction is decoded as an instruction and thus participates in locating subsequent instructions even if it is not the target of a branch. Only instructions can appear in the instruction stream, even if unreachable. There are no address-relative data addressing modes and raw data cannot be directly embedded within the instruction stream. Certain instructions allow embedding of immediate data as part of the instruction; however that differs from allowing raw data embedded directly in the instruction stream. Unreachable code can appear as the result of machinegenerated code and is allowed, but it shall always be in the form of properly formed instruction sequences.

The instruction stream can be translated and the associated instruction block discarded prior to execution of the translation. Thus, even instructions that capture and manipulate code addresses, such as call, ret, etc. can be virtualized to operate on translated addresses instead of addresses in the CIL instruction stream. end note

III.1.7.2 Valid branch targets

The set of addresses composed of the first byte of each instruction identified in the instruction stream defines the only valid instruction targets. Instruction targets include branch targets as specified in branch instructions, targets specified in exception tables such as protected ranges (see Partition I and Partition II), filter, and handler targets.

Branch instructions specify branch targets as either a 1-byte or 4-byte signed relative offset; the size of the offset is differentiated by the opcode of the instruction. The offset is defined as being relative to the byte following the branch instruction. Note: Thus, an offset value of zero targets the immediately following instruction.

The value of a 1-byte offset is computed by interpreting that byte as a signed 8-bit integer. The value of a 4-byte offset is can be computed by concatenating the bytes into a signed integer in the following manner: the byte of lowest address forms the least significant byte, and the byte with highest address forms the most significant byte of the integer. Note: This representation is often called “a signed integer in little-endian byte-order”.

III.1.7.3 Exception ranges

Exception tables describe ranges of instructions that are protected by catch, fault, or finally handlers (see Partition I and Partition II). The starting address of a protected block, filter clause, or handler shall be a valid branch target as specified in §III.1.7.2. It is invalid for a protected block, filter clause, or handler to end without forming a complete last instruction.

III.1.7.4 Must provide maxstack

Every method specifies a maximum number of items that can be pushed onto the CIL evaluation stack. The value is stored in the IMAGE_COR_ILMETHOD structure that precedes the CIL body of each method. A method that specifies a maximum number of items less than the amount required by a static analysis of the method (using a traditional control flow graph without analysis of the data) is invalid (hence also unverifiable) and need not be supported by a conforming implementation of the CLI.

Note: Maxstack is related to analysis of the program, not to the size of the stack at runtime. It does not specify the maximum size in bytes of a stack frame, but rather the number of items that shall be tracked by an analysis tool. end note

Rationale: By analyzing the CIL stream for any method, it is easy to determine how many items will be pushed on the CIL Evaluation stack. However, specifying that maximum number ahead of time helps a CIL-to-native-code compiler (especially a simple one that does only a single pass through the CIL stream) in allocating internal data structures that model the stack and/or verification algorithm. end rationale

III.1.7.5 Backward branch constraints

It shall be possible, with a single forward-pass through the CIL instruction stream for any method, to infer the exact state of the evaluation stack at every instruction (where by “state” we mean the number and type of each item on the evaluation stack).

In particular, if that single-pass analysis arrives at an instruction, call it location X, that immediately follows an unconditional branch, and where X is not the target of an earlier branch instruction, then the state of the evaluation stack at X, clearly, cannot be derived from existing information. In this case, the CLI demands that the evaluation stack at X be empty.

Following on from this rule, it would clearly be invalid CIL if a later branch instruction to X were to have a non-empty evaluation stack

Rationale: This constraint ensures that CIL code can be processed by a simple CIL-to-nativecode compiler. It ensures that the state of the evaluation stack at the beginning of each CIL can be inferred from a single, forward-pass analysis of the instruction stream. end rationale

Note: the stack state at location X in the above can be inferred by various means: from a previous forward branch to X; because X marks the start of an exception handler, etc. end note

See the following for further information:

  • Exceptions: Partition I
  • Verification conditions for branch instructions: §III.3
  • The tail. prefix: §III.3.19

III.1.7.6 Branch verification constraints

The target of all branch instruction shall be a valid branch target (see§III.1.7.2) within the method holding that branch instruction.


III.1.7 CIL符号列の制限事項

CILコードシーケンスに関する詳細な制限と同様に、以下を保証する。

  • 正しい CIL
  • 検証可能なCIL

単純なCIL-トーナティブコードコンパイラの構築を容易にするために、さらにいくつかの制限事項がある。このサブセクションでは、個々の命令について記載されている制限に加えて、適用される一般的な制限を指定します。 このサブセクションでは、個々の命令について記載されたものに加えて適用される一般的な制限を指定します。

III.1.7.1 命令ストリーム

メソッドの実装は、以下のように符号化されたCIL命令の連続したブロックによって提供されます。によって提供されます。メソッドの命令ブロックのアドレスとその長さは、ファイル形式(第II部、CIL物理レイアウト参照)で指定されます。ファイルフォーマットで指定されています(第II部「CIL物理レイアウト」参照)。最初の命令は,その1バイト目(最下位アドレス)にある。最初の命令は、命令ブロックの1バイト目(最下位アドレス)にあります。

命令の大きさは可変です。各命令のサイズは、命令バイトの内容そのものから判断(デコード)できる。各命令のサイズは、命令バイトの内容自体から決定(解読)できます。命令内のバイトのサイズと順序は、各命令定義で指定されます。命令内のバイトのサイズと順序は、各命令定義によって指定されます。命令はパディングなしで互いに続く アライメントやバイト順序に依存しないバイトストリームで、パディングなしに命令が続きます。

各命令は正確なバイト数を占め、命令ブロックの終わりまで続きます。次の命令は次のバイトから始まります。命令ブロックの長さによって指定される)命令ブロックは無効である。ブロック長で指定される)命令ブロックが、完全な最後の命令を形成せずに終了することは無効です。

命令プレフィックスは、新しい命令を導入することなく、命令の長さを延長します。1つ以上の接頭辞を持つ命令では、最初の命令接頭辞の1バイト目から始まる1つの命令だけが導入されます。1つ以上のプリフィックスを持つ命令は、最初の命令プリフィックスの1バイト目から始まる1つの命令のみを導入します。

注:命令ブロックの終わりまで、制御転送命令に続く命令は、命令としてデコードされ、命令ブロックの終わりまで、制御転送命令に続く命令は、命令としてデコードされます。注:命令ブロックの終了までは、制御転送命令の後に続く命令は命令としてデコードされ、後続の命令の探索に参加する。たとえそれが分岐対象でなくても。命令ストリームに現れることができるのは、命令だけです。たとえ到達不可能であっても。アドレス相対のデータアドレシングモードがなく、生データを直接命令ストリームに埋め込むことはできない。命令ストリームに直接データを埋め込むことはできません。特定の命令では、命令の一部として即時データを埋め込むことができる。しかし、これは命令ストリームに直接RAWデータを埋め込むこととは異なります。命令ストリームに直接埋め込むことはできません。到達不能コードは、機械が生成したコードの結果として現れることがあり、許可されるが、それは常に適切に形成された命令列の形式でなければならない。シーケンスでなければならない。 命令ストリームは翻訳され、翻訳実行前に関連する命令ブロックが破棄されることがある。翻訳を実行する前に、関連する命令ブロックを破棄することができる。したがって、コード・アドレスを捕捉し操作する命令であっても、call、retなど。call、retなどのコードアドレスを捕捉し操作する命令も、CIL命令ストリームのアドレスではなく、翻訳されたアドレスで操作するように仮想化することができる。CIL命令ストリームのアドレスではなく、翻訳されたアドレスで動作するように仮想化することができる。 エンディングノート

III.1.7.2 有効な分岐先

命令ストリームで識別される各命令の最初の1バイトで構成されるアドレスのセットは、唯一の有効な命令ターゲットを定義します。は、唯一の有効な命令ターゲットを定義する。命令ターゲットには、分岐命令で指定された分岐ターゲット 分岐命令で指定された分岐先、保護範囲などの例外テーブルで指定された分岐先(パーティションI、パーティシ (パーティションIおよびパーティションII参照)、フィルタ、およびハンドラターゲットが含まれます。

分岐命令では、分岐ターゲットを1バイトまたは4バイトの符号付き相対オフセットで指定します。オフセットのサイズは、命令のオペコードによって区別されます。オフセットは、分岐命令に続くバイトからの相対値として定義されます。[注:したがって、オフセット値が 0 の場合は、その直後にある命令が対象となります]。

1 バイトのオフセットの値は、そのバイトを符号付き 8 ビット整数として解釈して計算されます。4バイトのオフセットの値は、バイトを次のように符号付き整数に連結することで計算できます:最下位アドレスのバイトが最下位バイトを形成し、最上位アドレスのバイトが整数の最上位バイトを形成します。注:この表現はしばしば "リトルエンディアン・バイトオーダーの符号付き整数 "と呼ばれる。

III.1.7.3 例外範囲

例外テーブルは、catch、fault、またはfinallyハンドラによって保護されている命令の範囲を記述します。ハンドラによって保護される命令の範囲を記述します (パーティション I とパーティション II を参照)。保護されたブロック、フィルタ節、ハンドラの開始アドレスは、有効な分岐先でなければならない。またはハンドラの開始アドレスは、III.1.7.2節に規定されるように有効な分岐先でなければならない。保護されたブロック、フィルタ節またはハンドラでは無効である。ブロック、フィルタ節、ハンドラが完全な最後の命令を形成することなく終了することは無効である。

III.1.7.4 maxstack を提供する必要がある。

すべてのメソッドは、CIL 評価スタックにプッシュできるアイテムの最大数を指定する。この値は、各メソッドの CIL 本体の前にある IMAGE_COR_ILMETHOD 構造体に格納される。メソッドの静的解析 (データの解析を行わない従来の制御フローグラフを使用) で必要とされる量よりも少ない最大アイテム数を指定するメソッドは無効であり (したがって検証も不可能)、適合する CLI の実装によってサポートされる必要はありません。 の実装でサポートされる必要はない。

注:Maxstackはプログラムの解析に関連するものであり、実行時のスタックのサイズに関連するものではない。スタックフレームの最大サイズをバイト単位で指定するのではなく、解析ツールによって追跡されるべきアイテムの数を指定する。 注記

理由:任意のメソッドのCILストリームを分析することによって、CIL評価スタックにプッシュされるアイテムの数を決定することは容易である。しかし、前もってその最大数を指定することは、CILからネイティブコードへのコンパイラ(特に、CILストリームを1回だけ通過する単純なもの)がスタックや検証アルゴリズムをモデル化する内部データ構造を割り当てる際に役立つ。

III.1.7.5 逆方向分岐制約

CIL命令ストリームを1回前進させるだけで、あらゆるメソッドについて評価スタックの正確な状態を推測することが可能でなければならない。評価スタックの正確な状態を推論することが可能でなければならない(ここで「状態」とは,評価スタック上の各項目の番号と型を意味する)。評価スタック上の各項目の番号と型を意味する)。

特に、そのシングルパス解析が、ある命令(ロケーションXと呼ぶ)に到達すると 無条件分岐の直後で、かつ、Xが以前の分岐命令の対象でない場合、シングルパス解析は、評価スタックの状態 Xの評価スタックの状態は、明らかに既存の情報からは導き出せません。この場合、CLIは評価スタックの状態を要求します。この場合、CLIはXの評価スタックが空であることを要求する。

このルールからすると、Xへの分岐命令で評価スタックが空でない場合は、明らかにCILが無効となる。への分岐命令が空でない評価スタックを持つ場合、このルールは明らかに無効なCILとなる。

理由:この制約により、CILコードが単純なCIL-to-nativecodeコンパイラで処理できることが保証される。これは、各CILの先頭の評価スタックの状態が、命令ストリームの単一のフォワードパス解析から推測できることを保証するものである。

注:上記における位置Xのスタック状態は、様々な手段によって推論することができる:Xへの前の順方向分岐から。Xへの前のフォワードブランチから、Xが例外ハンドラの開始をマークしているから、など。

詳細は以下を参照。

  • 例外について パーティションI
  • 分岐命令の検証条件。§III.3節
  • テール(tail)接頭辞。§III.3.19節

III.1.7.6 分岐検証制約

すべての分岐命令のターゲットは,その分岐命令を持つメソッド内で有効な分岐ターゲット(第III.1.7.2項参照)でなければならない。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment