ページへ戻る

+ Links

 印刷 

OT​/0005 :: OSASK計画

osaskwiki:OT/0005

OSASKアプリのフォーマット anchor.png

Page Top

(1) anchor.png

  • 第一世代OSASKの実行ファイルのフォーマットは、ヘッダなどが多少あるものの、結局は.textそのものだった。ヘッダも.textの一部として扱った。エントリポイントはオフセット0からで、ファイルはそのままコードセグメントのイメージになっている。これは「はりぼてOS」よりも単純な構造といっていいだろう。
  • こういう仕様にしたのは理由がある。こうすればページ例外がおきるたびにそのページをロードすればいい。もしこれが何らかの構造を持つファイルで、その内容もメモリに展開するには多少の加工が必要、なんてものだったら、起動時に一度全部加工して、その後ページングによってスワップアウトされなければいけない(メモリが足りない場合)。
  • .dataの初期イメージは、.textには直接は入っていない。ただし間接的には入っている。というのは、.dataの内容を初期化するのはOSの責任ではなく、アプリのスタートアップルーチンの仕事になっているからである。
  • .textは必ずセグメントのオフセット0からに配置されるので、それに合わせたバイナリになっている。したがってリロケーション情報などはない。
  • シグネチャは8バイトあった(オフセット+8~+15:GUIGUI00)。
Page Top

(2) anchor.png

  • これに対し第二世代OSASKアプリのフォーマットは複雑である。COFFやELFほどではないが、しかしこれらと同じように複数のセクションを持ち、リロケーションのための情報を持ち、ファイル内のセクションイメージはメモリイメージとは必ずしも一致しない(一致しないのはもちろんリロケーション加工の差異のため)。
  • ヘッダやシグネチャもあるが、これらは.textセクションの一部ではない。というのは、ファイル全体が単純なコードセグメントのイメージではなくなった以上、よけいなヘッダやシグネチャをコードセグメントに含めておく意味が無くなったためである。
Page Top

(3) anchor.png

  • さらに第二世代OSASKアプリのフォーマットには、ファイルサイズを小さく保つ工夫がある。
  • 簡易モード。
    • セクションは.textのみで、スタックは1MB、ヒープサイズ2MBを準備する簡易モードを用意した。多くの簡易プログラム向けにはおそらくこれで十分である。必要な分を正確に指定したい場合や、足りない場合は、簡易モードは使わずに普通に記述する。
    • 簡易モードでは、ヘッダ等が終わって.textのイメージが始まると、ファイル末尾までが.textイメージだと見なされる。
    • ほぼ同等の仕様はCOM64plusにもある。
  • .textの末尾にC3を自動付加。
    • これはreturn;のコードである。実際多くのアプリを書いて実験したところ、第二世代OSASKアプリの.textの最後はC3になることが非常に多かった。それゆえ、それを省略可能にするため、この仕様を導入した。また末尾がC3ではない.textも稀に存在するが、そういうものに対してC3が勝手に付加されたところで、コードの末尾に一度も実行しないゴミが付くだけでしかないので、問題はない。
    • ほぼ同等の仕様はCOM64plusにもある。
  • .dataの末尾に32バイトの00を自動付加。
    • これも上記と同じように多くのアプリを書いて実験した。そうすると、.dataの末尾32バイトがもし00なら、それを利用することでアプリをコンパクトにしやすいことが分かった。この特性を利用しないとしても、それは.dataの末尾に32バイトの一度も読み書きしないゴミが付くだけでしかないので、問題はない。
    • ほぼ同等の仕様はCOM64plusにもたぶんある。
  • .textの先頭に、CALL([ESI]);のコードを付加可能。
    • これはオプションビットで付加するかどうかを指定する。やはり多数のアプリを書いて実験したところ、最初にいきなりAPI-CALLするアプリが多かった。そういうアプリは当然最初にAPI-CALLである、CALL([ESI]);を実行する。この2バイトを付加できるようにすることで、.textを2バイト削減することが可能である。
    • 類似の仕様はCOM64plusにもある。
  • レジスタ初期値指定フィールドを設定。
    • アプリの起動時のレジスタ値に付いて、これをカスタマイズできるオプションがある。こんなものを使わなくても.textの最初のほうでMOVを使って適切な値を入れればそれでいいのだが、このアプリヘッダ内のレジスタ初期値指定機能を使うほうが、ファイルサイズを少し節約できる(場合が多い)。これは値の指定にgh4エンコードが使えるからである。
  • 終了時の'\n'補完出力。
    • これもオプショナルで、実行ファイル内のフラグで有効・無効を設定する。これは、アプリ終了時に「最後にコンソール出力した文字が'\n'」でなければ、'\n'を出力してから終了する、というものである。これがあると多くのプログラムをコンパクトにしやすいことが分かっているので、この機能をつけた。
    • ほぼ同等の仕様はCOM64plusにもある。
Page Top

(4) anchor.png

  • hello1.g01 (17バイトのhello)
    47 01 05 51 "hello, world\0"
    • 最初の 47 01 はシグネチャ。次の4bitの0が「簡易モード」を意味している。次の5はフラグで、「CALL([ESI]);の付与」と、「終了時の'\n'補完出力」を要求している。またC3も末尾に自動付加される。結果として、.textは次のようになる。
      CALL([ESI]); DB(0x51, "hello, world\0"); return;
    • APIの引数については、OT​/0004の例を参照のこと。
    • 16バイトのhelloは、この12バイトのメッセージを7bitエンコードすることで11バイトに縮めたもの。
  • chars.g01 (13バイト)
    47 01 08 9a 00 55 16 00 40 3C 7F 72 F6
    • 最初の 47 01 はシグネチャ。次の4bitの0が「簡易モード」を意味している。次は89だが、これはgh4エンコードされた9のこと。この9は、「CALL([ESI]);の付与」と、「終了時の'\n'補完出力」に加え、「EAXの初期値設定」を指定。次のa0もgh4エンコードされた0x20のこと。これがEAXの初期値となる。次の0はパディングのために入っているだけなので無視される。そして結果として、.textは次のようになる。
      do { CALL([ESI]); DB(0x55, 0x16, 0x00); EAX++; } while ((unsigned) AL < 0x7f); return;
    • APIの引数については、OT​/0004の例を参照のこと。
Page Top

こめんと欄 anchor.png


Last-modified: 2009-11-21 (土) 00:00:00 (JST) (319d) by k-tan