仮想オペコード

AVR32 StudioについてくるGAS(Gnu ASM)には仮想オペコードというのがあり、これはAVR32 Architecture Manualに載っていない。それでいてプロジェクトのテンプレートに含まれているので、ソースコードを追っていると面食らってしまう。
仮想オペコードの情報は、AVR32 Studioインストール・ディレクトリのAVR Tools\AVR32 Toolchain\share\info\as.infoの「9.5.4 Opcodes」にある。infoファイルはテキスト・エディタでも見ることが出来るが、たしかフォーマットして表示するビューワinfoが必要となる。ところどころ「!」とか記号が出てくるが、これは文字ではなく、制御記号なのでエディタで見るときには無視する必要がある。
「9.5.4 Opcodes」に記述がある仮想オペコードは2つだけなので、ここにまとめておく。


LDA.W

lda.w   REG, SYMBOL

この命令はSYMBOLのアドレスをREGにロードする。命令は、シンボルと定数プールへの相対距離、そして--picオプションに依存し、以下の内1つに評価される。

--pic
の有無
評価条件展開されるコード
無し SYMBOLは十分小さな値と見なす。mov REG, SYMBOL
「. - SYMBOL」は十分小さな値と見なす。sub REG, pc, . - SYMBOL
固定データ・プール(CPENT)は閉じられている。 lddpc REG, CPENT

...

CPENT:

.long SYMBOL

その他(まだ実装していないが、たぶんその必要はない)mov REG, lo(SYMBOL)

orh REG, hi(SYMBOL)
有り「. - SYMBOL」は十分小さな値と見なす。
sub REG, pc, . - SYMBOL
オプション--linkrelaxが無い
ld.w REG, r6[SYMBOL@got]
その他
mov REG, SYMBOL@got / 4

ld.w REG, r6[REG << 2]
SYMBOLが同一ファイルやLDA.W命令と同一セクションで未定義のとき、上記のうち最も悲観的な選択肢を選択する。リンカは、全シンボル値を確定したとき、最も最適な選択肢へ戻していく。

CALL

call    SYMBOL

この命令は、SYMBOLで識別される関数呼び出しコードを挿入する。
--linkrelaxや--picのコマンド・オプションによるシンボルとの相対距離に依存した条件により、以下の1つに評価する。

SYMBOLが同一セクションかつ同一ファイルで定義されていて、かつ十分距離が小さいなら、rcall命令が挿入される。

    rcall   SYMBOL

それ以外で、--picオプションが無ければ次のようになる。

    mcall   CPENT
        ...
CPENT:
    .long   SYMBOL

最後に、--picオプションがあるなら、アセンブラはグローバル・オフセット・テーブルを経由した間接呼び出しを挿入する。

    /* If `--linkrelax' not specified */
    mcall   r6[SYMBOL@got]

    /* If `--linkrelax' specified */
    mov     lr, SYMBOL@got / 4
    ld.w    lr, r6[lr << 2]
    icall   lr

SYMBOLの最終値が決定した後、リンカは最適な選択肢により、上記のいくつかを変更するかもしれない。これらは削除できる余分な定数プールとGOTエントリを含んでいる。