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


GCCの出力とのインターフェイス

GCCは、 ターゲット・システム上で通常使用されている関数呼び出し規約を使うよう 構成(configureの実行)されているのが通例です。 これは、 マシン記述マクロ(machine-description macro)によって行われます (@xref{Target Macros})。

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

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

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

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

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

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

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

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

{
  int careful;
  &careful;
  ...
}

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

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

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


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