インラインアセンブルコード
sdccのCコンパイラの出力コードの効率があまりりよくないことはお話しました。 そのため、インラインアセンブルを使うことも多いでしょう。 インラインアセンブルの利用は、他のコンパイラ同様、以下のような利点があります。
- 特定の部分のみ高速化できます。
- Cプリプロセッサが働くので、#defineの定義が利用できます。
インラインアセンブルコードは、関数内に__asm~__endasm;で囲んで書きます。例えば、次のようになります。
static char *message; void func() { // 他のコード... __asm ld hl, #_message call _show_message _endasm; // 他のコード... }
この例では、アセンブルコードからCコードのmessageを参照しています。 ローカル変数の参照も出来ないことはないのですが、第2回で説明したように、スタック上の位置が宣言の順番に依存するので、避けた方がいいと思います。
警告の抑制
インラインアセンブラを使ってコードを書くと、
myprog.c:10: warning 85: in function myfunc unreferenced function argument : 'arg'
という警告が出てしまうことがあります。これは、関数の引数をアセンブルコード内のみで利用し、Cコード内で参照しないためです。sdccは__asm~__endasm;で囲まれた部分はそのままアセンブラに渡し、一切検査しません。
この警告が気になるなら、#pragmaで抑制することができます。
#pragma save #pragma disable_warning 85 void func(char* arg) { __asm // アセンブルコード... __endasm; } #pragma restore
#pragma save
でこれまでのpragma情報をいったん保存し、
#pragma disable_warning 85
でwarning 85の出力を抑制します。そのままだとこれ以降ずっとwarning 85が出なくなってしまうので、関数終了時に
#pragma restore
でpragma情報を元に戻します。
naked関数
アセンブルコードで関数本体を書いても、第2回で説明したよ うなixのバックアップ~リストアは出力されます。場合によってはこれが不都合なこともあります。そのため、__nakedという予約語があります。この 予約語がついた関数は、一切のプリアンブルコードが出力されません。retすらしません。そのため、全て自分で書く必要があります。
void func(char* arg) __naked { __asm // アセンブルコード... // retも自分ですること __endasm; }
インラインアセンブラTips: 関数ポインタの定数化
sdccでは、コードセグメントにおける関数ポインタの定数化ができません。 たとえば、以下のようなコードがあったとします。
char func1(int x) { ... } char func2(int x) { ... } char func3(int x) { ... } const char (*functions[])(int) = { func1, func2, func3 };
ここでfunctionsは定数ですので、コードセグメント内に配置して欲しいところなのですが、 sdccはfunctionsをデータエリアに置き、メンバの初期化をGSINIT内に出力します。そのため、非常に効率の悪いコードになるだけでなく、 本来の意味での定数ではなくなっています。
これを、naked関数を使って解決する手段があります。 次のように書きます。
char func1(int x) { ... } char func2(int x) { ... } char func3(int x) { ... } extern char (*functions[])(int); static unsigned char* __functions() __naked { __asm _functions:: .dw #_func1 .dw #_func2 .dw #_func3 __endasm; }
お分かりでしょうか。C言語からはfunctions外部変数を参照するようにしておいて、実はnaked関数内で定義しています。 なお、スコープをstaticにすることも可能です。その場合は、
_functions:
と、コロンをひとつにします。
上記の場合、メンバとなるfunc1, func2, func3の定義がプロトタイプ宣言と異なっていてもコンパイルエラーは出ません。これは良し悪しで、わざと違う定義にすることもあるかもしれません。た とえば、呼び出し側は常に引数を渡すようにしているが、呼び出された側はその引数を必要としないので、シグネチャに入れない、などということも考えられま す。
これを柔軟性と見るか、悪い設計だと見るかは、アプリケーションに依存するでしょうね。
匿名
画面が真っ暗、でもカーソルは出てる状況。
探して、ここにたどり着きました。
パスワード入力で、復活!
修理に出す寸前でした。ホントにありがとう!