3回目では条件分岐処理の解説をします。
解説の前に
解説の前にちょっと別のお話。
昨日ふと、そういえば「アセンブラ」と「アセンブリ」をちゃんと分けて書いていたかな?と思い、「うん、自信を持って全部『アセンブラ』って書いたと言えるな」という状況でした。
ということで突っ込みが入る前に早々に修正しときました。
今までの解説を見直して何か変わってない?って思ってもきっと気のせいですからスルーして下さい(^_^;)
ちなみに「アセンブラ」と「アセンブリ」の関係をC言語と比較するとこんな感じです。
ASM | C |
---|---|
アセンブラ | コンパイラ |
アセンブリ(アセンブリ言語) | C言語 |
「アセンブラ」に対応するものは「コンパイラ」になります。みなさんも間違えない様に気を付けましょう。
まあ、今は結構すべてを「アセンブラ」って記述してある事が多かったりするんですけどね。WikipadieaによるとIBMではアセンブラ言語って言ってるみたいですしね。
なお、「インラインアセンブラ」についてはAdaっていう言語での解説なのですがここで「Inline Assembler」と書かれていたり、
Inline Assembler - GNAT User's Guide
http://gcc.gnu.org/onlinedocs/gcc-4.2.3/gnat_ugn_unw/Inline-Assembler.html#Inline-Assembler
こちらのgccでのアセンブリコードの埋め込み方法の解説ページでも「Assembler Instruction」などとの記述がありますので「インラインアセンブラ」については「アセンブラ」で良い様です。
Extended Asm - Using the GNU Compiler Collection (GCC)
http://gcc.gnu.org/onlinedocs/gcc-4.2.3/gcc/Extended-Asm.html#Extended-Asm
条件分岐
ちょっと話がそれましたが解説に戻ります。サンプルプログラムはこの様になります。
__asm__ volatile ( "1: \n\t" "add %0, %0, #1 \n\t" "subs %1, %1, #1 \n\t" "bne 1b \n\t" : "+r" (val1), "+r" (loop) : : "cc" );
分岐処理は以下の部分で行っています。
bne 1b
bne の b の部分が本来の命令の部分が本来の命令部分であり、「条件が当てはまった場合に指定の場所へ(今回の場合は 1 へ)ジャンプする」命令です。
条件についてはこちらのサイトが分かり易くまとまってます。
Assembly Programming on Linux Zaurus(2)
http://www.mztn.org/slasm/arm02.html#cd
今回使用している bne では ne を使っている事になります。
こちらを確認すると条件は「Zクリア」と書いてあります。
NE 等しくない Zクリア Z=0
Z とはZフラグの事で計算や比較結果で0となったときにフラグがセット(フラグが立つ)されます。
Zクリアとの解説があるのでフラグがクリア(フラグが立ってない)状態の場合にジャンプするという命令になります。
このZフラグですがどこで変更が発生するかと言うと以下の命令です。
subs %1, %1, #1
こちら本来は前回解説した。 sub (引き算命令)なんですけど最後に s を付ける事で計算結果が各種フラグに反映されます。
この記述をC言語で表すとこうなります。
loop = loop - 1
loopの値が1づつ減算され0になった(Zフラグがセットされた)ときに条件が当てはまらなくなりジャンプされなくなります(ループが終了します)。
破壊されるデータの情報(clobber list)
今回のサンプルでは3つ目の : のブロックを使っています。
__asm__ volatile (
"(アセンブラの記述)"
:(出力オペランドに対応するCの式)
:(入力オペランドに対応するCの式)
:(破壊されるデータの情報)
);
ここにはインラインアセンブラ内で破壊(データを上書き)されるものを指定します。 subs で状態フラグ(ステータスレジスタ)に変更がかかるため、 "cc" を記述しています。
この記述を忘れていても動作する場合も有りますが「場合によっては発生する」というやっかいなバグを埋め込む事になるので忘れずに記述しておくようにしましょう。
iPhoneでインラインアセンブラを使うのエントリー一覧はこちら