ARMには即時データをロードする機能が制限されているため、ARMのコードを生成するユーティリティは、コードとデータを頻繁に並置します。たとえば、次のようなステートメント
void myRoutine(void)
{
myVar1=0x12345678;
myVar2=0x87654321;
}
次のような結果になる可能性があります。
myRoutine:
ldr r0,=myVar1; Load the address of _myVar
ldr r1,=0x12345678
str r1,[r0]
ldr r0,=myVar1; Load the address of _myVar
ldr r1,=0x87654321
str r1,[r0]
bx lr
which would get translated into:
ldr r0,dat1
ldr r1,dat2
str r1,[r0]
ldr r0,dat3
ldr r1,dat4
str r1,[r0]
bx lr
... followed some time later by
dat1 dcd _myVar1
dat2 dcd 0x12345678
dat3 dcd _myVar2
dat4 dcd 0x12345678
or perhaps even something like:
mar r0,dat1
ldrm r0,[r1,r2,r3,r4]
str r2,[r1]
str r4,[r3]
bx lr
... followed some time later by
dat1 dcd _myVar1
dat2 dcd 0x12345678
dat3 dcd _myVar2
dat4 dcd 0x12345678
_myVarと0x12345678は、それらが表示されるルーチンのコードの直後に配置できることに注意してください。最後の命令に続くラベルを使用してルーチンの長さを決定しようとすると、そのような長さには補足データが含まれません。
ARMで注意すべき追加の点は、歴史的な理由から、コードが実際にはハーフワード境界で開始されている場合でも、コードアドレスの最下位ビットが設定されることが多いということです。したがって、アドレスが0x12345679の命令は、0x12345678から始まる2バイトまたは4バイトのいずれかを占有します。これにより、memcpyなどのアドレス計算が複雑になる可能性があります。
私の推奨は、必要なことを行うためにアセンブリ言語で小さなルーチンを書くことです。ほんの数命令で、コードが何をしているのか、どのアドレス依存関係があるのかを正確に知ることができ、将来のコンパイラバージョンが何かを壊すような方法でコードを変更することを心配する必要はありません[例:3番目上記のコードのバージョンはdat1
、M3のLDR命令が非整列読み取りを処理できるため、奇数のハーフワード境界に到達しても問題ありませんが、LDRMを使用する4番目の(わずかに高速でコンパクトな)バージョンはそのような場合に失敗します。現在のバージョンのコンパイラが4つのLDR命令を使用している場合でも、将来のバージョンではLDRMを使用する可能性があります]。