ぐだぐだ低レベルプログラミング(6) インラインアセンブラ、gccで書き換えてみれば

前回は、MbedのWeb開発環境を使ってでしたが、Arm純正のツールチェーンで、「極小」のアセンブラ記述を行ってみました。そのとき、gccのインラインアセンブラで書くならばチト面倒いかもみたいなことを書いてしまいました。そのままというのも気持ちが悪いので、今回は実際に対応するコードをRaspberry Pi 3上のgcc用に書いてコンパイルしてGo。

※「ぐだぐだ低レベルプログラミング」投稿順indexはこちら

まずは、Nucleo用にMbed OSで書いたコードを、「Quickに」ラズパイに移植してみたコードをそのまま貼り付けますです。普通にコンパイルすれば動く筈。

まず、Arm純正の環境では組み込みアセンブラを使い、__asmで修飾した「関数」として以下のように記述したadd3_embasm()ですが、

// Arm純正ツールチェーン用
__asm int add3_embasm(int i)
{
    add r0, #3
    bx lr
}

gcc用では2つの部分に分けて記述する方法しか考えつきませんでした。こういう方法で良いのかな。ちゃんとコンパイルできて動いているので、まあよしとしていますが。

//gcc用
int add3_embasm(int i);

asm (
    "add3_embasm:\n\t"
    " add r0, #3\n\t"
    " bx lr\n\t"
);

アセンブラ本体に並べた命令は同じなのですが、インラインアセンブラの中に関数名ラベルを記述し、それとは別に同名の関数プロトタイプまで記述してあります。そういえば、gccでインラインアセンブラ使用する場合、いつも

asm volatile

みたいに volatileつけるのが定番ですが、ここではつけていません。C関数の中にインラインコードを書くと、Cコンパイラは前後のコードと一緒に最適化してしまい、アセンブラで意図する通りのシーケンスにならないことがあるからのvolatileです。しかし、asmキーワードをCの関数の外側に置いた場合、Arm純正の組み込みアセンブラ同様、gccもCコードの最適化の埒外でそのままアセンブラ用のソースに「一旦は」落としてくれるようです。書いても悪くはないですが、volatile不要。しかし、関数プロトタイプとアセンブラの中のラベルというのは2重定義のようで気持ちがちょっと悪いです。関数プロトタイプはそういう名の関数が「ある」ことと、引数と戻り値の型をコンパイラに知らせるためのもの。アセンブラソースの中のラベルこそ、実際にオブジェクト生成するときに参照される実体であります。

ただ、gccのマニュアルを読んでいるとどうしてよいか分からない部分がありました。最適化の結果コードが消えてしまったりすることは無い反面、アセンブラに落ちた後も低レベルの最適化が進行するようで、必要あれば同じコードを複数個所に配置することがあるとのこと。「その場合、ラベル使っていると2重定義になる」とのことであります。ローカルなラベルなら自動生成に任せるのも手ですが、関数名ではな。うーむ、デュプリケートされてしまうのは、どんな時なのだろうか?後の課題であります。

次にCのコード内の「普通の」インラインです。純正の方は変数名をそのまま書ける(逆に言うとレジスタ名を書いてはいけない)ので、非常にシンプル。

// Arm純正ツールチェーン用
 __asm("add vb, i");

これに対して、gccの方は、変数とレジスタの接続方法を書いてやらねばなりませぬ。こちらの方が多分皆さまおなじみのスタイル

//gcc用
asm( "add %[Rd1], %[Rs1] \n\t"
    : [Rd1] "=r" (vb)
    : [Rs1] "r" (i)
    :
);

アセンブラはたった1行のaddだけなんです。しかし、その後のコロンに続き、まず出力の定義、[Rd1]はマクロといわれるもの。アセンブラの中で%付きでデスティネーションとして参照しているもの。その後の “=r” こそコンストレイントなるもの。=印は書き込み、rはレジスタ。そして(vb)はこの記述にvbという変数を束縛する意味。つまりは、vbという変数に代入されるべき値がどこかのレジスタに入っており、そのレジスタ名をアセンブラ「テンプレート」(addの行はテンプレートなのです)の中で%[Rd1]なる形で参照できると。次のコロンの後は今度は入力の方の定義ですがまあ後は推して知るべしということで割愛いたします。最後のコロンの後は破壊するリソースをコンパイラに知らせる行。

gccにはお世話になっているし、これからもお世話になるつもりですが、私的には、Arm純正の方がシンプルで書きやすく思えるのですがねえ。どんなもんでしょうか。

ぐだぐだ低レベルプログラミング(5) Arm 組み込みアセンブラとインラインアセンブラ へ戻る

ぐだぐだ低レベルプログラミング(7) .syntax、コメント、ローカルラベル へ進む