🐫

ARMとunaligned memory accessの歴史

2022/04/29に公開

記憶の範囲で書いています。要件証。
1990年代後半から2000年代初め頃の話です。

unaligned memory access とは

メモリアクセスでは、そのアクセスするサイズによって都合の良いアドレスがあります。
これをメモリのアライメントと言います。
16bitデータなら、偶数アドレスつまり2の倍数。
32bitデータなら4の倍数。
64bitデータなら8の倍数。
これらにそろっていないアドレスからのデータアクセスをunaligned memory accessと言います。

パソコンの普及で広く世の中で使われたx86系のCPUは当初からunaligned memory accessに対して寛容でした。しかし他の多くのCPUはそうではありません。
x86系以外の多くのCPUではunaligned memory accessのときにはバスエラーなどの例外が発生するので、そのことに気が付くことができますが、それを全部修正していく必要があります。
x86系向けに作られたライブラリなどを他のCPUに移植するときに、これは頭痛のタネになりました。

以下にARMシリーズでのunaligned memory accessの歴史を紹介します。

ARM7

unaligned memory accessでは揃っていないアドレスの下位ビットを勝手に無視してアクセスします。
つまり、0x10000003 からの16bitのデータリードは勝手に0x10000000から読み出します。
これはひどい。
当然意図と異なる数値が読めることになるので、どこかしばらくたったところで想定外の異常動作になります。
これは悪夢でした。これのデバッグはつらかったあ。

ARM9

コプロセッサのレジスタ設定により、unaligned memory accessの時に例外を発生させることができるようになりました。これで他のCPUと同じになりました。

ARM11以降

ARM9の設定に加えて、unaligned memory accessを許可することができるようになりました。
これによって、x86系向けに作られたライブラリの移植で、アライメントの調整で頭を悩ますことから解放されました。
もちろんアクセス速度に関しては、unaligned memory accessは通常のアクセスよりも遅くなるというペナルティはあります。

Cコンパイラのコンパイルオプション

Cコンパイラにunaligned memory accessをするようなコードを出力させるかどうかをコンパイルオプションで指定することができます。
gccでは-munaligned-access です。
詳細はこちら

unaligned memory accessは遅いのですが、場合によってはそれをするほうがコードサイズが小さくなることがあるので、このオプションをつけるとコンパイラはそういうコードを出力します。

余談

ARM11以降unaligned memory accessができるようになったときに、Linuxカーネルは早い時期から-munaligned-access をつけることがデフォルトになりました。
一方、U-Bootは保守的で、-munaligned-accessをつけるかどうか割と長い間議論されていました。今はLinuxカーネルと同等になっています。
私はちょうどその頃に、ある評価ボード向けのパッチをLinuxカーネルとU-Bootのそれぞれに投稿してマージしてもらいました。

余談2

ARM7を使った携帯電話のプロジェクトが進行している頃に、ARMの方からARM11の説明を受けました。
そのときの第一印象は「こんな化け物のようなCPUが携帯電話に使われるとは思えない」でした。
でも現在のスマフォで使用されているCPUの進化はみなさんも知っての通り。

ARM11は今だとラズパイゼロに載っているやつです。

今、NVIDIAから発表されたロボティックス向けのSoCを見て、「こんな化け物が」と思いますが、数年のうちにそのくらいは普通になるのでしょうね。

Discussion