R78/L13 アセンブラのインライン展開について

お世話になってます。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;

}

逆アセンブルの内容

void main(unsigned char* a, unsigned short b )

_main:

       2006        SUBW            SP,#6H

       b802        MOVW            [SP+2H],AX

       13          MOVW            AX,BC

       b804        MOVW            [SP+4H],AX

              func(a, b);                        

 

       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

       13          MOVW            AX,BC

       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],AX
    13 MOVW AX,BC
    B810 MOVW [SP+10H],AX

    ではないかと思います。意味不明なコードは何でしょうね...(笑

    もし、inline_asm 関数本体が、何かをスタックに退避しなければいけないほど複雑になるなら、チョコさんのアドバイスのように、アセンブリ言語の関数を呼び出した方が良いかもしれません。

  • チョコです。

    poposuさん、以下のmain関数の定義はおかしいですね。

    void main(unsigned char* a, unsigned short b )

    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     スタック領域に保存

                  func(a, b);                        

    12          MOVW            BC,AX          funcを呼び出すためにAXレジスタの引数bをBCに設定

           a802        MOVW            AX,[SP+2H]     引数aをスタック領域から読み出す

    このようにスタック領域を作業領域として  データを保管するようになっています。勿論、SPの値は関数から戻る直前に作業領域を解放するために、元に戻すようになっています。

    以上