私がコードを書いている ARM (Cortex M0) が、アラインされていないメモリ アクセスをサポートしていないことを発見しました。
現在、私のコードでは多くのパックされた構造体を使用していますが、警告やハードフォールトは一度も発生していません。では、アライメントされていないアクセスが許可されていない場合、Cortex はこれらの構造体のメンバーにどのようにアクセスできるのでしょうか?
私がコードを書いている ARM (Cortex M0) が、アラインされていないメモリ アクセスをサポートしていないことを発見しました。
現在、私のコードでは多くのパックされた構造体を使用していますが、警告やハードフォールトは一度も発生していません。では、アライメントされていないアクセスが許可されていない場合、Cortex はこれらの構造体のメンバーにどのようにアクセスできるのでしょうか?
gcc などのコンパイラはアラインメントを理解し、アラインメントの問題を回避するための正しい命令を発行します。パックされた構造体がある場合は、コンパイラーにそのことを伝えているので、アラインメントの方法を前もって知ることができます。
32 ビット アーキテクチャを使用しているが、次のstruct
ようにパックされているとします。
struct foo __attribute__((packed)) {
unsigned char bar;
int baz;
}
へのアクセスbaz
が行われると、32 ビット境界でメモリのロードが行われ、すべてのビットが所定の位置にシフトされます。
この場合、おそらく のアドレスの32 ビット ロードと、+ 4bar
のアドレスでの 32 ビット ロードになりますbar
。次に、シフトや論理 OR/AND などの論理演算のシーケンスを適用して、最終的に正しい結果になります。の値をbaz
32 ビット レジスタに格納します。
アセンブリの出力を見て、これがどのように機能するかを確認してください。これらのアーキテクチャでは、整列されていないアクセスは整列されたアクセスよりも効率が悪いことに気付くでしょう。
多くの古い 8 ビット マイクロプロセッサでは、メモリ バスの幅よりも大きなレジスタをロード (および保存) する命令がありました。このような操作は、あるアドレスからレジスタの半分をロードし、次に高いアドレスから残りの半分をロードすることによって実行されます。メモリ バスが 8 ビット幅 (たとえば 16 ビット) よりも広いシステムでも、メモリをアドレス指定可能なバイトの集まりと見なすと便利なことがよくあります。任意のアドレスからバイトをロードすると、プロセッサは 16 ビットのメモリ位置の半分を読み取り、残りの半分を無視します。偶数アドレスから 16 ビット値を読み取ると、プロセッサは 16 ビット メモリ ロケーション全体を読み取り、すべてを使用します。値は、2 つの連続したバイト アドレスを読み取り、結果を連結した場合と同じになりますが、2 回ではなく 1 回の操作で読み取られます。
このようなシステムの一部では、奇数アドレスから 16 ビット値を読み取ろうとすると、プロセッサは 2 つの連続するアドレスを読み取ります。バイトが読み取られ、結果が結合されます。これは、アラインされていないメモリ アクセスと呼ばれます。他のシステムでは、このような操作によりバス障害が発生し、一般に何らかの形の割り込みがトリガーされ、何らかの有用な処理を実行できる場合と実行できない場合があります。非境界整列アクセスをサポートするためのハードウェアはかなり複雑であり、非境界整列アクセスを回避するコードの設計は、一般的にそれほど難しくありません。したがって、そのようなハードウェアは通常、すでに非常に複雑なプロセッサ上にのみ存在します。