パックされていない struct__packed struct、および個々に __packed で修飾されたフィールドを持つ struct の詳細な比較

Table 17 は、struct をパックしなかった場合、struct 全体をパックした場合、および struct の個々のフィールドをパックした場合のそれぞれの違いを、struct の 3 種類の実装で示したものです。

最初の実装では、struct がパックされていません。2 番目の実装では、構造体の全体が __packed として修飾されています。3 番目の実装では、__packed 属性が構造体から削除され、個々の非自然境界整列フィールドが __packed として宣言されています。

Table 17. パックされていない struct、パックされた struct、および個々のフィールドがパックされた struct を表す C コード

パックされていない structパックされた structパックされたフィールド
struct foo
{
    char one;
    short two;
    char three;
    int four;
} c;
__packed struct foo
{
    char one;
    short two;
    char three;
    int four;
} c;
struct foo
{
    char one;
    __packed short two;
    char three;
    int four;
} c;

Table 18 は、コンパイラによって生成されたマシンコードが Table 17 の各実装例でどのように逆アセンブルされるかを示したものです。いずれの実装の C コードも、オプション -O2 を使用してコンパイルされています。

Note

非境界整列要素へのアクセスをインラインと関数呼び出しのどちらで行うかは、-Ospace および -Otime の各コンパイラオプションによって制御されます。-Otime を使用すると、インラインの非境界整列アクセスが行われます。-Ospace を使用すると、関数呼び出しによる非境界整列アクセスが行われます。

Table 18. パックされていない struct、パックされた struct、および個々のフィールドがパックされた struct を表す逆アセンブリコード

パックされていない structパックされた structパックされたフィールド
; r0 は c のアドレスを格納する
; char one
LDRB    r1, [r0, #0]
; short two
LDRSH   r2, [r0, #2]
; char three
LDRB    r3, [r0, #4]
; int four
LDR     r12, [r0, #8]
; r0 は c のアドレスを格納する
; char one
LDRB  r1, [r0, #0]
; short two
LDRB  r2, [r0, #1]
LDRSB r12, [r0, #2]
ORR   r2, r12, r2, LSL #8
; char three
LDRB  r3, [r0, #3]
; int four
ADD   r0, r0, #4
BL    __aeabi_uread4
; r0 は c のアドレスを格納する
; char one
LDRB  r1, [r0, #0]
; short two
LDRB  r2, [r0, #1]
LDRSB r12, [r0, #2]
ORR   r2, r12, r2, LSL #8
; char three
LDRB  r3, [r0, #3]
; int four
LDR   r12, [r0, #4]

Table 18 に示すパックされていない struct の逆アセンブリの場合、コンパイラは、境界整列型ワードまたはハーフワードのアドレス上にあるデータに必ずアクセスします。コンパイラがこれを行うことができるのは、struct の全メンバがデータ自身と同じサイズの境界上に配置されるように、struct にパッドが挿入されているためです。

Table 18 に示す __packed struct の逆アセンブリでは、フィールド onethree は、データ自身と同じサイズの境界にデフォルトで境界整列されているので、コンパイラは境界整列型アクセスを行います。コンパイラは、境界整列されていることが識別できるフィールドに対して、境界整列型のワードアクセスまたはハーフワードアクセスを必ず実行します。非境界整列型フィールド two に対しては、複数の境界整列メモリアクセス(LDR/STR/LDM/STM)を特定のシフト命令およびマスク命令と組み合わせて使用し、メモリ内の正しいバイトにアクセスします。コンパイラは、フィールドがデータ自身と同じサイズの境界上にあるかどうかを判定できないので、不明な境界整列の符号なしワードを読み出すための ARM 組み込みアプリケーションバイナリインタフェース(AEABI)ランタイムルーチン __aeabi_uread4 を呼び出して、フィールド four にアクセスします。

Table 18に示す、フィールドが個々にパックされた struct の逆アセンブリでは、struct 全体が __packed として修飾されている場合と同様に、フィールド onetwo、および three がアクセスされます。しかし、struct 全体がパックされる場合と異なり、コンパイラはフィールド four に対してワード境界整列型のアクセスを行います。これは、構造体内の __packed short の存在に基づいてフィールド four がデータ自身と同じサイズの境界上にあることをコンパイラが判定できるからです。

Show/hide関連項目

Copyright © 2010 ARM. All rights reserved.ARM DUI 0472BJ
Non-ConfidentialID011811