2001年7月30日 作成

Using PRC-Tools
■戻る■  ■トップ■  ■進む■


extralogue 属性とエントリポイント

extralogue 属性は、関数のプロローグとエピローグとに、 任意のコードを追加するのに用いられる。 基本的な使用法として、 関数の寿命に対して、分離されたグローバルポインタを初期化するために、 owngp 属性と結合させて用いられる。 ENTRYPOINT マクロは、 ちょうどこの目的のために、`EntryPoints.h' で定義されている:


  #define ENTRYPOINT(EXTRAS)  \
    __attribute__ ((__owngp__, __extralogue__ EXTRAS))

0 から 8 のパラメータを取り、 それぞれ、 asm のテンプレート文字列と同じ文法を持った文字列である。 (Using and Porting GCC の `Assembler Instructions with C Expression Operands' を参照のこと。):


  extralogue (prologue, epilogue, single-epilogue, void-epilogue,
              far-prologue, far-epilogue, far-single-epilogue, far-void-epilogue)

これは困難に見えるが、ほとんどのパラメータは必要ない。 引数が空(i.e. "")である場合、下記のように、置き換えが選択される。 ある点を越えてすべての引数が空である場合、すべてを省略できる。 一般的に、ひとつかふたつのパラメータを指定するだけでよい。 その理由は下記の通りとなる:

  • `far-' がつく引数は、 デフォルトでないセクションにおける関数が特殊な扱いを必要とする場合にのみ用いられる。 `特殊な扱い' とは、マルチプルセクションを実装するのに用いられるグローバル変数を含むような場合である。 従って、グローバル変数へのアクセスを調停するために用いられる extralogue は、 そのような特殊な扱いを要求しないほうが無難である。
  • メインの epilogue は、すべてのエピローグをハンドルできる。 `single-' がつく引数と `void-' がつく引数とは、 だいたいの場合において、より効果的なコードを生成するが、 本当に必要ではない。
  • 実は、特殊なエピローグは全然必要ではない。

このように、実際は、extralogue はひとつの引数でしか使用しない。 例えば、CALLBACK_* マクロと同義のものとして ENTRYPOINT がある:


  ENTRYPOINT (("move.l %%a5,%%a4; sub.l #edata,%%a4"))

ENTRYPOINT は、マクロであるが、varargs をエミュレートするのにふたつの括弧が要求される。

この属性の使用例については `EntryPoints.h' を参照のこと。

Prologues

prologue 関数は、まず、スタックへ現在の A4 の値をセーブするコードを生成する。 次に、以下の条件に合うものを生成する:

far-prologue functionsection 属性を持っている場合
prologue

選択された文字列は、 関数の最初のパラメータのアドレスを参照するために %0 を使用できる。 %0 は、 offset(fp) 又は offset(sp) の Mode 5 EA である。

prologue は、スタックに余分なデータを残したはならない。 もし、prologue と epilogue とが互いにコミュニケーションを取り、 それぞれの要求が A4 で満たされない場合、 関数にて、格納スペースとしていくつかローカル変数を宣言すべきである。 その場合、 FP から適切なオフセットでアクセスするため、 テンプレートを用意するのがいいだろう。

しかし、`-fomit-frame-pointer' を使用する場合、これが機能しない。 この場合、asm で追加の epilogue を偽造しなければならないだろう。 こうすることで、コンパイラが SP からの正確なオフセットを算出できる。 古い CALLBACK_EPILOGUE を用いる場合、 実行形式が `epilogue' を通過しなければ関数から脱出できないよう保証しなければならない。

Epilogues

epilogue 関数は、次のうち条件に合うものを生成する:

far-void-epilogue functionsection 属性を持ち、レジスタを返す必要がない場合
far-single-epilogue functionsection 属性を持ち、高々ひとつのレジスタを返す必要がある場合
far-epilogue functionsection 属性を持つ場合
void-epilogue function がレジスタを返す必要がない場合
single-epilogue function が高々ひとつのレジスタを返す必要がある場合
epilogue

選択された文字列は、 関数の返り値を参照するために %0 を使用できる。 もし、関数が、その値を返すために、いくつかのレジスタを要求する場合 (例えば、long long を D0 と D1 とを使って返す場合)、 %0movem 命令に適したレジスタリストとなり得る。 関数がひとつのレジスタで値を返す場合、%0 はそのレジスタを表す。 返り値の型がポインタかどうかで、 %%d0%%a0 のどちらかを表すことになる。 一方、関数が void であったり、大きい構造体を返す場合、 %0 は常に %%a0 を表す。

最後に、epilogue は、スタックから古い A4 の値をリストアするコードを生成する。

The `far-' variants

デフォルトでないセクションの関数が含まれ、 通常のテンプレートが適切に機能しないとき、 `far-' がつく引数を与えなければならない。 (これは、最適化の問題ではなく、 `far-' がつく引数は一般的に、 シングルコードリソースの実行形式で機能しないため、 epilogue 引数に対するケースである。 普通、そのような引数は、 __text__ シンボルを使用しなければならないために必要とされる。 シングルコードリソースの実行形式では、リンクエラーが発生してしまうだろう。)

ふたつの追加オペランドが、`far-' テンプレートで有効となる。 %a1 は、 関数のセクションの `__text__section' シンボルであり、 %2 は、 メインのテキストセクションのベースポインタを表すグローバルのアドレスである。 例えば、それが __text__(%%pic) であるなら、 その %%pic は A4 又は A5 である。 (これは動的に、なぜ `far-' がつく引数が ENTRYPOINT と共に用いられることがあり得ないことかを示している。 それは、レジスタがまだセットアップされないうちに、 A4 を通じてテキストセンクションのベースポインタへアクセスするのに あまり使用されない。)

`far-' の引数が必要とする extralogue の他の使用法がある。 例えば、プロファイルを行う関数を、関数の開始地点で呼出すよう調整する場合、次のようになる:


  #define CALL_PROFILER \
    __attribute__ ((extralogue ("bsr.w __count", "", "", "",
                                "move.l %2,%%a0; jsr __count(%%a0)")))
  int f() CALL_PROFILER;

セクションをまたがったジャンプが必要とされ、 それを使用することをコンパイラに指定できない場合、 section 属性を持つ関数で使用される CALL_PROFILER マクロを、個別に用意しなければならない。 これは不思議なエラーをまねき、間違ったマクロを使用すると、プログラムがクラッシュしてしまうだろう。

代わりに、次のようにプロファイルを行う関数を呼出せばよい:


  int f() {
    __count();
    ...
    }

いい例ではないが、有望なことに、問題を明らかにしている。 多分、誰か柔軟性のあるよい方法を見つけてくれるだろう。


■戻る■  ■トップ■  ■進む■