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

4.34.1 グローバルレジスタ変数の定義

GNU C ではグローバルレジスタ変数を以下のように定義することができる。

 
register int *foo asm ("a5");

ここで a5 は、使用したいレジスタ名である。 レジスタはその機種で関数呼び出しで退避/復帰されるものを 選ぶようにしておくと、ライブラリルーチンで値が破壊されることがない。

当然レジスタ名は CPU に依存するので、CPU タイプに応じてプログラムを 条件で分ける必要がある。a5 というレジスタは、68000 の場合は ポインタ型の変数向けとしては、良い選択である。 レジスタウィンドウを持つ機種の場合は、「グローバル」なレジスタを 選ぶようにし、関数呼び出し機構により影響を受けないようにする必要がある。

さらに、同じ CPU タイプでもその上で動作する OS によっては、 レジスタの呼び方が違う場合がある。その場合はさらに場合わけが必要に なる。例えば、68000 で動作する OS の中には上記の例のレジスタを %a5 と呼ぶものもある。

将来的にはコンパイラに自動的にレジスタを選ぶように指示する手段が あって良いだろうが、まず、どのようにして選択すべきか、そして その選択を読者が知るにはどのようにしたら良いかを明らかにしなければ ならない。明らかな解決手段はないのである。

グローバルレジスタ変数をあるレジスタに割り当てると、 少なくともコンパイル単位内では、そのレジスタはその目的にだけ使われる。 現在のコンパイル単位内の関数では、他の用途にそのレジスタが 割り当てられることはない。 また、このコンパイル単位内の関数で退避/復帰されることもない。 このレジスタへの格納は、死んでいるように見えても決して削除されないが、 参照は削除されたり、移動されたり、簡素化される可能性がある。

グローバルレジスタ変数をシグナルハンドラや、一つ以上の制御スレッドから アクセスするのは安全ではない。というのは、システムのライブラリルーチンが そのレジスタを別の目的で一時的に使う可能性があるからである。 (システムのライブラリルーチンをその目的のために特別にコンパイルし直せば その限りではないが。)

グローバルレジスタ変数を使っている関数が、別のやはりグローバルレジスタ 変数を使っている関数 foo を、この変数についての情報無しに (例えば、この変数が宣言されていない別のソースファイルにある等) コンパイルされた三番目の関数 lose を経由して呼び出すのは 危険である。これは、lose がそのレジスタをセーブした上で何か他の 値を置く可能性があるからである。例えば、qsort に渡す 比較関数の中でグローバルレジスタ変数を使えると思ってはいけない。 qsort が、何か他のものをそのレジスタに置く可能性があるからである。 (qsort を同じグローバルレジスタ変数を使うように再コンパイル すれば、この問題は解消する。)

qsort や他のソースファイルで、実際にはグローバルレジスタ変数を 使っていないものを再コンパイルして、そのレジスタを他の目的には使わないように したければ、‘-ffixed-reg’ オプションを指定すれば充分である。 実際にソースコードにグローバルレジスタの宣言を追加する必要はない。

グローバルレジスタ変数の値を変え得る関数は、この変数なしでコンパイルした 関数からは安全に呼び出すことができない。呼出し側が戻り値を見つける場所に ある値を書き換える可能性があるからである。このため、グローバルレジスタ 変数を使っているプログラムの途中への入り口点となる関数は、 呼出し側に所属する値を明示的にセーブ/リストアしなければならない。

ほとんどの機種では、longjmp は、各グローバルレジスタ変数に、 それらの変数の setjmp の時点での値をリストアする。 しかし、中には longjmp がグローバルレジスタ変数の値を 変えない機種もある。移植性を良くするためには、setjmp を 呼び出す関数は、グローバルレジスタ変数をセーブし、longjmp の 中でそれらをリストアするように調整を行なわなければならない。 こうしておけば、longjmp が何をするかに関わらず同じ動作が 期待できる。

全てのグローバルレジスタ変数の宣言は、全ての関数定義の前になければ ならない。もしグローバルレジスタ変数の宣言が関数定義の後に 現れても、その宣言では先行する関数でそのレジスタが別の目的で 使われるのを防ぐことができない。

グローバルレジスタ変数は初期値を持つことができない。 実行形式ファイルには、レジスタの初期内容を提供する方法がないからである。

SPARC では、g3 〜 g7 がグローバルレジスタに適しているとの 報告がある。ただし、幾つかのライブラリ関数、例えば、getwd や、 除算と剰余算のサブルーチンは g3 と g4 を修正する。g1 と g2 は ローカルの一時レジスタである。

68000 では、a2 〜 a5 と d2 〜 d7 が適している。 当然ながら、これらのうちの 2,3個ではなく、もっとたくさん使うのは適していない。


This document was generated using texi2html 1.78.