プロが教えるわが家の防犯対策術!

gcc Ver2.9 でSH-2の開発をしています。
通常に関数を作成し、引数を渡しているのですが、引数が渡らないという現象が起きています。
現象は、
1.引数はポインタではなく値渡しである
2.引数の値が0の時だけ正しく渡らない。値が0以外の時は正常にわたる
3.引数の型は一致している
4.引数は複数あるが、後半のいくつかがだめ(何個とまでは詳しく調べていません)
5.ある特定の関数の特定の呼び出しのみがだめで全てだめというわけではない
6.コンパイルオプションに -m2 をつけるとだめだが、-m1 オプションだと問題ない
7.最適化オプションをなくしても同じだった
といった状況です。

上記5からある特定の記述方法とか順序になるとだめになるのではないかといろいろ試してみたのですが見つけられません。6から記述方法に誤りがあるとも考えにくい状況です。コンパイラのバグといって片付けていいものなのかどうかです。どなたか同じような経験をされた方はいらっしゃいませんか。また関数呼び出しの場合、コンパイラがどうやって引数を渡すかご教授願えませんか。

A 回答 (3件)

イミディエイト値の0だけで発生する現象のようですね。



0Lや0Uでも同じ現象でしょうか?

イミディエイトな0だけが問題を起こすならint ZERO = 0;のようなグローバル変数を定義して、0の代わりに使うという手も…
    • good
    • 0
この回答へのお礼

ご意見ありがとうございます。
残念ながらイミディエイト値の0だけで発生するわけではありません。
変数であってもその値が0とコンパイル時にわかる場合はだめなようです。
したがってローカル変数でint ZERO = 0;のように定義してもだめです。
しかし仰るようにグローバル変数でint ZERO = 0;のように定義すればコンパイル時にその値が0であるかどうかはわかりませんのでうまく回避できるようです。
しかし調子に乗って、const int ZERO = 0;などとやると変数の値が固定されてしまうのでコンパイラに0であることがバレて(笑)だめになってしまいます。

一応、その他の回避方法を試行錯誤で調べましたので書いておきます。但しコンパイラそのものを解析したわけではありませんので絶対にOKという保証はありません。

1.引数の数を4個以下にする。
2.引数リストの中にコンパイル時点で0になる計算式を含めない
3.0の引数は、引数リストの先頭に持ってくる

とりあえずこれで問題は起きてないみたいです。

お礼日時:2003/01/10 16:30

現在スタックへのプッシュ・ポップで引数を渡すコンパイラというのはほとんど存在しないでしょう。


効率が悪すぎ、関数呼び出しの度に大きなオーバーヘッドになります。

SH-2のアーキテクチャを良く知らないで、以下は一般論です。

1.レジスタが豊富で引数用レジスタが用意できる場合(RISCに多い)
SPARCなどで採用されている方法です。
レジスタのうちの10~20個程度を引数要に割り当てます(引数がそれ以上の場合は2の方法を併用)。
更に下位の関数を呼び出す場合はスタックに退避し、関数から戻ったときにレジスタに復帰します。
下位関数の呼び出しが無ければスタックへのアクセスが発生しないため、非常に高速です。

2.ベースポインタを利用する(CISCに多い)
スタック上の引数に対してベースポインタからの相対アドレッシングで直接アクセスします。
ベースポインタが用意されていないCPUでは汎用アドレスレジスタを流用します。
稀にスタックポインタをベースポインタとして利用することもあるようです。

3.引数領域を別途用意する
スタックが無く、レジスタに余裕が無い場合にのみ利用されます。
汎用コンピュータのCコンパイラで見られます。

スタックを利用する場合でもPUSH・POP(PULL)系の命令が使われることはほとんどありません。
1ワードを超えるデータ長の引数を扱うときに効率が悪くなるため、ベースポインタからの相対アドレスに対してMOVE系の命令を使うことが多いでしょう。

gccなら-Sオプションでコンパイルすればアセンブラ展開形が確認できると思います。
    • good
    • 0
この回答へのお礼

詳しい解説をありがとうございます。
デバッガで逆アセンブルをかけて解読しました。
結論は、コンパイラのバグのようです。

SH2は汎用レジスタの数が比較的少ないため、引数はレジスタとスタックで渡されています。
スタックはレジスタの相対アドレッシングで参照しています。問題の引数は通常、レジスタにイミディエイトで値をセットし、それをスタックにセットするという手順で渡されています。
ところが、問題の箇所で引数が0の場合、イミディエイトで値をセットする代わりに、MACレジスタの値を転送しています。
このMACレジスタがクリアされていれば問題ないわけですがそれは行われていません。
デバッガでクリアされない値が渡っていくことを確認しました。
コードで書くとこんな具合です。
(XXXXには相対アドレスが入ります)
正常時:
MOV     #0, R1
MOV.L   R1, @(XXXX,R15) ;これで引数セット

NG時:
STS    MACL, R1
MOV.L   R1, @(XXXX,R15) ;これで引数セット

残る問題は対策です。コンパイラのbugfixを待つのは正攻法ですが、そんな悠長なことは言ってられません。引数に0を使わないというのも無理があるし、引数0があるたびにMACレジスタクリアの命令を挿入するのも面倒だし弱っています。どういう記述をするとそうなるのかという法則を見出すしかないのでしょうか。

お礼日時:2002/12/26 13:37

引数がいくつかっていうのが気になりますが、


0というのは定数リテラルで渡してるんでしょうか?
それともConst定数でしょうか?それとも変数に格納したもので?

引数を渡すときは、最終的にスタック領域にプッシュして関数ポインタにジャンプしてスタックからポップという動きになるのはどのコンパイラでも一緒ですからねえ。。。
単なるコンパイラのバグと片付けてしまっていいと思いますよ。
どうしても気になるんでしたら、逆アセンブルをかけてアセンブラにしてトレースしていけば詳しい動きがわかりますよ。(結果は同じなんですけどね^^;)
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!