読者です 読者をやめる 読者になる 読者になる

アセンブラコードをCから呼び出す

アセンブラコードはマイコンの動作を理解するために、さけて通れない道。

さて、手持ちのfrdmk64fでどう学習すればよいのか。

インラインアセンブラというのは、どこかでチラっと読んだ気がするが、

gccによるアセンブルの結果であって、armasmによる純粋なアセンブラコード(*.s)の動作とは異なるものらしい。

それも気になるが、:[xx] "=r" (xx)の構文をそもそも避けたい事情がある。

というのも、IAR EWARMの逆アセンブル結果をみると、グローバル変数

位置するアドレスを一時的にR0なり、R1なりに突っ込んで動作している事があって、インラインアセンブラでコーディングしているR0, R1の実装を汚染してしまう。

それなら、素直に*.sで用意したらどうだろう、と思った次第。

しかしたぶん、これ、大変だと思う。IAR EWARM以外のfrdmk64fのプログラムダウンロード以外の方法を知らないので、正しいアプローチでないかもだけど、

まずはIARのサンプルとARMのヘルプセンターの情報をもとに、strcopy的な*.sを

IAR EWARMプロジェクトに追加してみた。コードは以下。

PUBLIC strcopy
SECTION .text:CODE:ROOT(2)
//ARM
strcopy:
LDRB R2, [R1], #1
STRB R2, [R0], #1
CMP R2, #0
BNE strcopy
BX lr
END

//ARMとあるのは、Cortex-M系ではそもそもARM32ビット命令をサポートしていない?ので、アセンブラに怒られてコメントアウトしたものである。

IARのサンプルは cp15.sという cortex-A系のコプロセッサを制御するサンプルだった

ので、さもありなんとゆーことか。

ちなみに、ARMのヘルプセンターには

    PRESERVE8
    AREA    SCopy, CODE, READONLY
    EXPORT strcopy
strcopy               ; R0 はデスティネーション文字列を指す
                      ; R1 はソース文字列を指す
    LDRB R2, [R1],#1  ; バイトをロードし、アドレスを更新する
    STRB R2, [R0],#1  ; バイトを格納し、アドレスを更新する
    CMP  R2, #0       ; NULL 終端文字をチェックする
    BNE  strcopy      ; NULL でない場合は続行する
    BX   lr           ; 復帰
    END
のように、「Cからのアセンブリ言語の呼び出し」には書いてあったけど、そうか、これ、
ARM Compiler 4 and 5 => Version 4.1 日本語版 => ARMコンパイラツールチェーン ARMプロセッサをターゲットとしたソフトウェア開発 => C、C++、およびアセンブリ言語の混用 => Cからのアセンブリ言語の呼び出し
に乗っていた情報であり、ver4系は古いのか?
そのせいか、IARのビルドでは「Bad instruction」が出てエラーとなっていた。
いや違うな、ver5でも、上記と同じサンプルが記載されている。
IARが独自でアセンブラ ディレクティブを削除した、とゆーことか。

呼び出し側は(当然ながら)ver4だろうが、C側なんで問題なく、
extern void strcopy(char* d, const char *s);
const char *srcstr = "First sring - source ";
char dststr[] = "Second string - destination ";
strcopy(dststr, srcstr);
PRINTF(" dst = %s\n", dststr);
でフツーに動いた、やった!!

ちなみにcのグローバル変数には以下のようにアクセスできた。
PUBLIC strcopy
SECTION .text:CODE:ROOT(2)
IMPORT q_ready
//ARM
strcopy:
MOV R3, #1
LDR R0, =q_ready
STR R3, [R0, #0]
BX lr
END

さて、SECTIONについても、IARアセンブラリファレンスガイドを調べてみた。
(くそ、なんで、ARMインフォメーションセンターだけで済まないんだ)

ROOT、NOROOT ROOT(デフォルトモード)は、セクション フラグメントを破 棄してはならないことを示します。 NOROOT は、このセクション フラグメント内のシンボルが参 照されない場合、セクション フラグメントがリンカによ り破棄されることを意味します。通常、起動コードと割 込みベクタを除くすべてのセクション フラグメントで、 このフラグを設定する必要があります。
なるほど、NOROOT(2)に変えておいた。数字はアライン指定らしい。しかしなんで2なんだろう? CprtexM系は32ビットマイコンなのに・・Thumb命令だから?