[Contents]   [Back]   [Prev]   [Up]   [Next]   [Forward]  


GNU CCの出力とのインターフェイス

GNU CCは、 ターゲット・システム上で通常使用されている関数呼び出し規約を使うよう設定(コンフィギュレーション)されているのが通例です。 これは、 マシン記述マクロ(machine-description macro)によって行われます (@xref{Target Macros})。

しかし、 構造体や共用体の値を戻り値とする方法は、 ターゲット・マシンによっては異なる方法で実現されています。 その結果、 PCCによりコンパイルされた関数のうち、 こうした型を戻り値とするものは、 GNU CCによりコンパイルされたコードからは呼び出すことができません。 逆もまた真です。 このようなことがあまり問題にならないのは、 Unixのライブラリ・ルーチンには、 構造体や共用体を戻り値とするものが少ししか存在しないからです。

GNU CCにより生成されたコードは、 サイズが1、2、4、または8バイトの構造体や共用体を戻り値とする際には、 int型やdouble型の値を戻り値とする際に使用するのと同じレジスタにその戻り値を入れて返します。 (GNU CCでは、 こうした型の変数もレジスタに割り当てられます。) 上記以外のサイズの構造体や共用体は、 呼び出し側から (通常は、 レジスタに入れて) 渡されたアドレスの指す領域に格納して返されます。 マシン記述マクロのSTRUCT_VALUESTRUCT_INCOMING_VALUEによって、 このアドレスをどこに入れて渡すかを、 GNU CCは知ります。

これに対して、 ほとんどのターゲット・マシン上において、 PCCは、 どのようなサイズの構造体、共用体であっても、 まずそのデータを静的記憶域にある領域にコピーしてから、 その領域のアドレスをポインタ値であるかのようにして返します。 呼び出し側では、 そのアドレスの指すメモリ域から、 値が必要とされる場所にデータをコピーしなければなりません。 このような方式は、 GNU CCの方式と比較して遅く、 再入可能でもありません。

例えば、 RISCマシンや80386のようないくつかのターゲット・マシン上では、 サブルーチンに対して、 値を戻す場所のアドレスを渡すというのが、 システム標準の規約になっています。 このようなマシン上でこの方式が採用されている場合には、 標準コンパイラの振る舞いと互換性を持つように、 GNU CCは設定(コンフィギュレーション)されてきました。 ただし、 サイズが1、2、4、8バイトのいずれかの構造体に関しては、 GNU CCは互換性を持たないかもしれません。

GNU CCは、 引数を渡す際には、 システムの標準規約を使います。 マシンによって、 最初の2,3個の引数がレジスタに入れて渡されたり、 すべての引数がスタック上に入れて渡されたりします。 どのようなマシン上でも、 引数を渡すのにレジスタを使うことは可能でしょうし、 そうすることによって、 性能もかなり向上するでしょう。 しかし、 それは結果として、 標準規約にしたがうコードとの完全な非互換性をもたらすことになります。 したがって、 そのような変更は、 GNU CCをシステム上の唯一のCコンパイラとして使うような状況でしか、 現実的ではありません。 GNUシステムが完成して、 ライブラリもGNU CCでコンパイルすることができるようになれば、 いくつかのマシン上で、 レジスタを使った引数渡しを実装することになるかもしれません。

いくつかのマシン(特に、Sparc)では、 特定の型の引数は「不可視の参照(invisible reference)を使って」渡されます。 これは、 値がメモリ上に格納され、 そのメモリ位置のアドレスがサブルーチンに渡される、 ということを意味しています。

longjmpを使う場合は、 自動変数に注意してください。 ANSI Cによれば、 volatile宣言されていない自動変数がlongjmpの後に持つ値は未定義です。 GNU CCにもこれ以上のことはできません。 レジスタ変数を正しく復旧することは非常に困難なのです。 GNU CCの特徴の1つは、 プログラマが要求しなくても、 変数をレジスタに入れることができるということです。

longjmpによって変数の値が変更されないようにしたいのであれば、 そして同時に、 古いCコンパイラが受け付けてくれないのでvolatileを使いたくないのであれば、 その変数のアドレスを取ってください。 ある変数のアドレスが取られている場合、 仮にそれが、 単にアドレスを計算した後に無視されるだけであっても、 その変数をレジスタに入れることはできなくなります。

{
  int careful;
  &careful;
  ...
}

GNU CCを使ってコンパイルされたコードが、 ある特定のライブラリ・ルーチンを呼び出すことがあります。 こうしたライブラリ・ルーチンのほとんどは、 対応するマシン命令の存在しない算術処理を実現するものです。 このような命令は、 いくつかのマシンでは乗除算命令です。 また、 `-msoft-float'の指定により浮動小数点サポートが無効になっているマシンでは、 浮動小数点操作がそれにあたります。 Cライブラリの標準構成要素のいくつか、 例えばbcopymemcpyも自動的に呼び出されます。 ライブラリ・ルーチンの呼び出しにも、 通常の関数呼び出しインターフェイスが使われます。

こうしたライブラリ・ルーチンは、 ライブラリ`libgcc.a'の中に定義されているはずです。 GNU CCは、 プログラムのリンク時に、 このファイルを自動的に探します。 乗除算命令を持つマシンで、 ハードウェアによる浮動小数点サポートが使われていれば、 `libgcc.a'は通常必要ありませんが、 万一に備えて、 GNU CCはこのファイルを探します。

`libgcc1.c'の中の個々の算術関数は、 対応するCの算術演算子を使うよう定義されています。 C言語のすべての算術演算子をサポートしている他のCコンパイラでコンパイルされている限り、 このファイルは移植性を持ちつつ機能します。 しかし、 GNU CCを使ってコンパイルされた場合は、 すべての算術関数が自分自身を呼び出すようにコンパイルされてしまうので、 `libgcc1.c'はうまく機能しません。


[Contents]   [Back]   [Prev]   [Up]   [Next]   [Forward]