[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

17.8 varargs マクロの実装

GNU CC には、‘varargs.h’ と ‘stdarg.h’ のある実装が付属しており、 引数をスタック上で渡す機種では変更なしで動作する。 そうでない機種ではそれ自身の varargs の実装が必要になり、 その場合、機種独立の二つのヘッダファイルから条件付きで実装ファイルを インクルードしなければならない。

ANSI の ‘stdarg.h’ は、旧来の ‘varargs.h’ とは、 va_start の呼び出し規約の点で主に異なっている。 旧来の実装では、va_start は引数をただ一つだけ取り、 それが引数ポインタを格納する変数になっている。 ANSI の va_start の実装では、引数が一つ追加されている。 プログラマは、関数の引数で名前が付いている最後のものを va_start の 二番目の引数に書くことを要求される。

しかし、va_start はこの二番目の引数を使うべきではない。 名前付き引数の最後を見つける方法は、以下に記述する組み込み関数で 行なう。

__builtin_saveregs ()

この組み込み関数を使って、引数レジスタをメモリにセーブすることで、 varargs の機構がそれらをアクセス可能になる。 va_start の ANSI 版も旧来版もどちらも、 代わりに SETUP_INCOMING_VARARGS(以下を参照)を使うのでない限り、 __builtin_saveregs を使わなければならない。

機種によっては、__builtin_saveregs はマクロ EXPAND_BUILTIN_SAVEREGS の制御の元で C 言語で書かれている。 その他の機種では、アセンブラ言語で書かれたルーチンを呼び出す。 これは、‘libgcc2.c’ にある。

__builtin_saveregs 呼び出し用に生成されたコードは、 __builtin_saveregs の呼び出しが書かれている場所とは 対照的に、そのコードが何をするかには関係なく、 関数の先頭に現れる。 これは、レジスタは、関数がそれ自身の目的でそのレジスタを使い始める前に セーブされなければならないものだからである。

__builtin_args_info (category)

この組み込み関数を使って、レジスタにある最初の無名引数を見つける。

一般に、一つの機種には、引数として使われるレジスタには色々なカテゴリが あり、それぞれ特定のデータ型のカテゴリに対して使われる。 (例えば、ある機種では、浮動小数点レジスタは浮動小数点引数に 使われる一方で、それ以外の引数は汎用レジスタで渡される。) 非 varargs 関数が正しい呼び出し規約を使用するようにするには、 データ型 CUMULATIVE_ARGS を定義して、各カテゴリで 何個のレジスタがこれまで使われたかを記録する必要がある。

__builtin_args_infoCUMULATIVE_ARGS 型と同じデータ構造 を、それを使った通常の引数のレイアウトが終わった後で参照する。 このとき、category がどのワードを参照すべきかを指定する。 つまり、この値は与えられたカテゴリのレジスタで未使用のものの先頭を指す。

普通は、va_start の実装で __builtin_args_info を 使い、各カテゴリを一度だけアクセスし、値を va_list オブジェクトに 格納する。これは va_list がその値を更新しなければならないためであり、 __builtin_args_info によりアクセスされる値を変える方法が ないためである。

__builtin_next_arg (lastarg)

これは、スタック上の引数については、__builtin_args_info に 等価である。先頭の無名スタック引数のアドレスを、void * 型で 返す。ARGS_GROW_DOWNWARD が定義されていれば、 先頭の無名スタック引数の上の位置のアドレスを返す。 それを va_start で使って、スタックから引数を取り出すための ポインタを初期化する。また、va_start で、 第二引数 lastarg が現在の関数の名前のある引数の最後で あることを検証するのにも使われる。

__builtin_classify_type (object)

それぞれの機種には固有の規約があって、どの型のデータをどの種類の レジスタで渡すかを決めている。読者はその規約を具体化するように va_arg を実装しなければならない。指定されたデータ型を 分類する一番手っ取り早い方法は、__builtin_classify_typesizeof__alignof__ を組み合わせて使うことである。

__builtin_classify_typeobject の値は無視し、 そのデータ型だけを見る。 どんな型であるか—整数、浮動小数点、ポインタ、構造体などを 記述する整数を返す。

ファイル ‘typeclass.h’ である列挙型を定義していて、 __builtin_classify_type の値を解釈するのに使うことができる。

以下のマシン記述マクロは varargs の実装を助ける。

EXPAND_BUILTIN_SAVEREGS (args)

定義されているなら、一個の C の式であり、__builtin_saveregs を 呼び出すための機種固有のコードを生成する。 このコードは関数の一番先頭の、仮引数のアクセスが行なわれる前に移動される。 この関数の戻り値は、__builtin_saveregs の戻り値として 使う値を含む RTX とすべきである。

引数 args は、__builtin_saveregs に渡された引数を 含む、ある tree_list である。

このマクロが定義されていない場合は、コンパイラは 通常の、ライブラリ関数 ‘__builtin_saveregs’ の呼び出しを 出力する。

SETUP_INCOMING_VARARGS (args_so_far, mode, type, pretend_args_size, second_time)

このマクロは、__builtin_saveregs の使い方とマクロ EXPAND_BUILTIN_SAVEREGS の定義の仕方に別の選択肢を提供する。 このマクロを使って、無名のレジスタ引数をスタックに格納し、 全ての引数がスタック上に連続して渡されたように見せることができる。 一旦これをやっておくと、varargs の標準の実装を使うことができる。 varargs の標準の実装は、全ての引数をスタックで渡す機種に対して 使うことができる。

引数 args_so_far はデータ構造 CUMULATIVE_ARGS である。 このデータ構造は、名前つき引数を処理した後の値を含む。 引数 modetype は最後の名前つき引数を、 そのマシンモードとデータ型をツリーノードとして記述する。

このマクロの実装では次の二つを行なう必要がある。 まず第一に、名前つき引数用に使われていない全ての引数レジスタを スタックにプッシュする。次に、このようにしてプッシュされたデータの 大きさを int 型の値の変数に格納する。この変数の名前は、 引数 pretend_args_size で提供される。ここで格納した値は、 スタックフレームの設定で使われる追加のオフセットとして機能する。

無名引数をプッシュするコードを、コンパイル時にそのデータ型を知ることなし に生成しなければならないので、SETUP_INCOMING_VARARGS は、 引数レジスタのカテゴリが一個しかなく、全データ型にたいして等しくそれを 使う機種でのみ、意味がある。

引数 second_time がゼロでないと、この関数の引数が二回目に 解析されることを意味する。これはインライン展開関数の場合に起こり、 ソースファイルの終りに達するまで実際にコンパイルされない。 マクロ SETUP_INCOMING_VARARGS は、この場合何も命令を生成すべきでない。

STRICT_ARGUMENT_NAMING

関数の引数が渡される位置が、その引数が名前付きの引数かどうかに 依存するなら、このマクロをゼロでない値に定義する。

このマクロは、FUNCTION_ARG への引数 named が varargs と stdarg 関数に対してどのようにして設定されるかを制御する。 このマクロがゼロでない値を返すなら、引数 named は名前つき引数に 対しては常に真になり、名無し引数では偽になる。 このマクロが値ゼロを返すが、SETUP_INCOMING_VARARGS が 定義されている場合は、全ての引数が名前つきとして扱われる。 それ以外の場合は、全ての名前つき引数は、最後の引数を除いて、 名前付きとして扱われる。

常にゼロを返すなら、このマクロを定義する必要はない。

PRETEND_OUTGOING_VARARGS_NAMED

ABI を条件により変更して、一方は SETUP_INCOMING_VARARGS が 定義されている場合に動作するようにし、もう一方は、 SETUP_INCOMING_VARARGSSTRICT_ARGUMENT_NAMING も 定義されていないかのように動作させる必要がある場合には、 このマクロを、SETUP_INCOMING_VARARGS が使われている場合には ゼロでない値を返すように定義し、使われていない場合にはゼロを 返すようにする。該当しな場合は、このマクロを定義すべきではない。


This document was generated using texi2html 1.78.