2001年7月30日 作成
Using PRC-Tools | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
■戻る■
■トップ■
■進む■
|
#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. "")である場合、下記のように、置き換えが選択される。 ある点を越えてすべての引数が空である場合、すべてを省略できる。 一般的に、ひとつかふたつのパラメータを指定するだけでよい。 その理由は下記の通りとなる:
extralogue
は、
そのような特殊な扱いを要求しないほうが無難である。
epilogue
は、すべてのエピローグをハンドルできる。
`single-' がつく引数と `void-' がつく引数とは、
だいたいの場合において、より効果的なコードを生成するが、
本当に必要ではない。
このように、実際は、extralogue
はひとつの引数でしか使用しない。
例えば、CALLBACK_*
マクロと同義のものとして ENTRYPOINT
がある:
ENTRYPOINT (("move.l %%a5,%%a4; sub.l #edata,%%a4")) |
ENTRYPOINT
は、マクロであるが、varargs をエミュレートするのにふたつの括弧が要求される。
この属性の使用例については `EntryPoints.h' を参照のこと。
prologue 関数は、まず、スタックへ現在の A4 の値をセーブするコードを生成する。 次に、以下の条件に合うものを生成する:
far-prologue | function が section 属性を持っている場合
|
prologue |
選択された文字列は、
関数の最初のパラメータのアドレスを参照するために %0
を使用できる。
%0
は、
offset(fp)
又は offset(sp)
の
Mode 5 EA である。
prologue は、スタックに余分なデータを残したはならない。 もし、prologue と epilogue とが互いにコミュニケーションを取り、 それぞれの要求が A4 で満たされない場合、 関数にて、格納スペースとしていくつかローカル変数を宣言すべきである。 その場合、 FP から適切なオフセットでアクセスするため、 テンプレートを用意するのがいいだろう。
しかし、`-fomit-frame-pointer' を使用する場合、これが機能しない。
この場合、asm
で追加の epilogue を偽造しなければならないだろう。
こうすることで、コンパイラが SP からの正確なオフセットを算出できる。
古い CALLBACK_EPILOGUE
を用いる場合、
実行形式が `epilogue' を通過しなければ関数から脱出できないよう保証しなければならない。
epilogue 関数は、次のうち条件に合うものを生成する:
far-void-epilogue | function が section 属性を持ち、レジスタを返す必要がない場合
|
far-single-epilogue | function が section 属性を持ち、高々ひとつのレジスタを返す必要がある場合
|
far-epilogue | function が section 属性を持つ場合
|
void-epilogue | function がレジスタを返す必要がない場合 |
single-epilogue | function が高々ひとつのレジスタを返す必要がある場合 |
epilogue |
選択された文字列は、
関数の返り値を参照するために %0
を使用できる。
もし、関数が、その値を返すために、いくつかのレジスタを要求する場合
(例えば、long long を D0 と D1 とを使って返す場合)、
%0
は movem
命令に適したレジスタリストとなり得る。
関数がひとつのレジスタで値を返す場合、%0
はそのレジスタを表す。
返り値の型がポインタかどうかで、
%%d0
か %%a0
のどちらかを表すことになる。
一方、関数が void であったり、大きい構造体を返す場合、
%0
は常に %%a0
を表す。
最後に、epilogue は、スタックから古い A4 の値をリストアするコードを生成する。
デフォルトでないセクションの関数が含まれ、
通常のテンプレートが適切に機能しないとき、
`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(); ... } |
いい例ではないが、有望なことに、問題を明らかにしている。 多分、誰か柔軟性のあるよい方法を見つけてくれるだろう。