お世話になってます。RL78/L13を使用しています。
開発環境はCS+ for CC
コンパイラはCC-RL V1.10
を使用しています。
C言語を用いてコーディングを行っていますが、
実行時間の関係で一部の関数をアセンブラのインライン展開を行う必要が出てきてしまいました。
アセンブラ記述はあまり知見がなく、
コンパイラのアセンブラソース出力で得られたアセンブラソースを参考に記述しました。
ビルドは通ったのですがコールスタックが消えてしまう現象が起こり、
プログラムが正常に動かない状態となってしまいました。
デバッグで調査を行ったところ、
逆アセンブラにてコンパイラで命令が追加や変更されており、その命令を通るとコールスタックが消えてしまうようでした。
コードをすべて記載すると長くなってしまうため、
ひとまず問題の箇所を抜粋したコードを記載させていただきます。
よろしくお願いいたします。
Cソースの記述
main関数内でアセンブラ記述したfuncを呼び出している。
#pragma inline_asm func
static void func(unsigned char* a, unsigned short b)
{
subw sp, #0x1A
movw [sp+0x0E], ax
movw ax, bc
movw [sp+0x10], ax
…
}
void main(unsigned char* a, unsigned short b )
unsigned char c;
unsigned char d;
func(a, b);
return;
逆アセンブルの内容
_main:
2006 SUBW SP,#6H
b802 MOVW [SP+2H],AX
13 MOVW AX,BC
b804 MOVW [SP+4H],AX
12 MOVW BC,AX
a802 MOVW AX,[SP+2H]
01 ADDW AX,AX
020408 ADDW AX,!804H
1020 ADDW SP,#20H
4080201a CMP !2080H,#1AH
b80e MOVW [SP+0EH],AX
B810 MOVW [SP+10H],AX
色の説明
青:アレンブラの出力ソースファイルでも追加が確認された部分
赤:逆アセンブルでのみ追加が確認された部分
緑:逆アセンブルで記述が変更されていた部分
チョコです。
関数funcが全てinlineアセンブルの対象であれば、関数funcそのものをアセンブラにすべきでしょう。
「CC-RLコンパイラ ユーザーズマニュアル(R20UT3123JJ)」の以下の内容を参照してアセンブリ言語の関数を呼び出すようにしてはいかがでしょうか。ちなみに、アセンブリ言語での関数名は「_func」とCでの名前の前に「_」(アンダースコア)を付けることになりますが。
以上
CC-RL コンパイラ ユーザーズマニュアル(Rev.1.13 2023.12)の「4. コンパイラ言語仕様」「アセンブラ命令の記述(#pragma inline_asm)」の説明を読む限り、CC-RL は、スタックフレームの内容を SP 相対でアクセスしているようなので、
> ビルドは通ったのですがコールスタックが消えてしまう現象が起こり、
の原因は、poposu さんが、func 中で「勝手に(コンパイラに無断で)」スタックポインタ(SP)を変更したためではないかと予想します。ただ、問題の箇所を抜粋したコードだけでは、正確な判断が下せませんが。 また、出力コードの見方は、多分、
12 MOVW BC,AX ; 実引数 b を BC レジスタにa802 MOVW AX,[SP+2H] ; 実引数 a を AX レジスタに01020408 ??? ; 意味不明なコード10204080 ??? ;201a SUBW SP,#1AH ; inline_asm 関数本体b80e MOVW [SP+0EH],AX13 MOVW AX,BCB810 MOVW [SP+10H],AX …
ではないかと思います。意味不明なコードは何でしょうね...(笑
もし、inline_asm 関数本体が、何かをスタックに退避しなければいけないほど複雑になるなら、チョコさんのアドバイスのように、アセンブリ言語の関数を呼び出した方が良いかもしれません。
poposuさん、以下のmain関数の定義はおかしいですね。
CC-RLのスタトアップからのmain関数の呼び出しは以下に示すように、引数なしで行われます。
なぜこのようなmain関数を定義したのでしょうか。
ご返答ありがとうございます。
処理としては、データ配列の行と列を入れ替えるような処理をしてます。
もう少しアセンブラについて記述を調べてみて、スタックポインタの処理について勉強してみます。
ご指摘いただいたアセンブリ関数の呼び出しも、試しにやってみて挙動を確認してみたいと思います。
チョコさん
誤解を招く情報の出し方をしてしまって申し訳ありません。
コードの抜粋としては、便宜上mainという名前の関数にしてますが、
実際は別の名称としています。
参考までにC記述の関数の逆アセンブル結果についてコメントしておきます。
2006 SUBW SP,#6H スタック領域に作業用領域として6バイト確保
b802 MOVW [SP+2H],AX 確保した領域に引数1(a)をスタック領域に保存
13 MOVW AX,BC 引数2(b)をAXレジスタにコピーし、
b804 MOVW [SP+4H],AX スタック領域に保存
12 MOVW BC,AX funcを呼び出すためにAXレジスタの引数bをBCに設定
a802 MOVW AX,[SP+2H] 引数aをスタック領域から読み出す
このようにスタック領域を作業領域として データを保管するようになっています。勿論、SPの値は関数から戻る直前に作業領域を解放するために、元に戻すようになっています。