1.2.1. 非境界整列ポインタ

C および C++ 標準では、ある型へのポインタは、その型の自然配列と同等以上のアライメントである必要があると定められています。これにより、効率的なコードサイズが生成され、パフォーマンスが向上します。このため、デフォルトでは、ARM コンパイラは通常の C および C++ ポインタがメモリ内の境界整列されたワードを指していると想定します。型修飾子 __packed を使用すると、非境界整列ポインタにアクセスできます(詳細については、RealView Compilation Tools v3.0 Compiler and Libraries Guideのコンパイラの参照での変数宣言キーワードについて説明したセクションを参照して下さい)。

例えば、ワードの読み出しにポインタ int * が使用される場合、ARM コンパイラでは、生成するコード内に LDR 命令を使用します。この命令は、アドレスが 4 の倍数(ワード境界)である場合に、期待どおりに実行されます。しかし、アドレスが 4 の倍数でない場合、LDR 命令では本来の非境界整列ワードのロードが実行されず、ロテートされた結果が返されます。ロテートされた結果は、オフセットやシステムのエンディアン設定によって異なります。

例えば、コードでアドレス 0x8006 を指すポインタからデータをロードする場合、0x80060x80070x8008、および 0x8009 からバイトの内容がロードされることが期待されます。しかし、ARM プロセッサでは、このアクセスでロードされるのは、アドレス 0x80040x80050x8006、および 0x8007 のバイトをロテートした内容です。

このため、任意のアドレス(つまり、自然配列によるアドレスでない)にあるワードを指すポインタを定義する場合は、ポインタを定義する際に、以下のように __packed 修飾子を使用してこのことを指定する必要があります。

__packed int *pi; // pointer to unaligned int

この場合、ARM コンパイラでは LDR を使用せずに、ポインタのアライメントに関係なくその値に正しくアクセスするコードを生成します。生成されるコードは、連続してバイトをアクセスするコードであるか、またはコンパイルオプションによっては、変数のアライメントに依存するシフト命令およびマスク命令になります。しかし、この方法では、パフォーマンスが低下し、コードサイズが増加します。

Note

ARM コンパイラではデータの取得に複数のメモリアクセスを使用する可能性があるため、メモリマップされたペリフェラルレジスタには __packed 修飾子を使用してアクセスしないで下さい。このようなアクセスを行うと、他のペリフェラルレジスタに対応する周辺の位置へのアクセスが行われる可能性があります。ビットフィールドを使用すると、現在の ARM コンパイラでは、指定されたフィールドだけでなく、コンテナ全体にアクセスします。

Copyright © 2002-2006 ARM Limited. All rights reserved.ARM DUI 0203GJ
Non-Confidential