ハードウェアを意識したプログラミングの基礎(後編)
最後にもう一つ別のARMのCPUボードで試してみます.今度使用するボードはArmadillo-500注2です.CPUには Freescale Semiconductor社の i.MX31を使用しています.i.MX31はARMv6アーキテクチャを採用しています.Armadillo-9で使用したものと同じバイナリをArmadillo-500上で実行してみましょう.
注2;以下のURLを参照. http://www.atmark-techno.com/armadillo-500
0x78563412
0x9A785634
0xBC9A7856
0xDEBC9A78
正しく読めました.実はARMv6アーキテクチャ以降ではunaligned accessがサポートされるようになったのです
注3.このように,アークテクチャによってunaligned accessを行ったときに異なる現象が発生します.デバイス・ドライバを一つのアーキテクチャで使用されている間は問題にならないのですが,ほかのアーキテクチャに移植するときには注意が必要です.
注3;このことを初めて知ったとき,筆者は1人で叫んだ.
● 問題になりそうで,ならないもの
それでは実際にプログラムを書いているときに問題になるのはどのような場合でしょうか.
C言語でプログラムを書いている場合,基本的にアドレスを指定してメモリを確保することはできません.スタックに取られる変数もアドレスはもちろんのこと,malloc()のようにヒープからメモリを確保する関数も,戻り値をそのままアドレスとして使用するだけです.リスト2のように整数を入れるために確保したヒープ・アドレスがアラインされていなければ,unaligned accessを起こしてしまいます.しかし,システム・ライブラリはCPUの制約を考慮しアラインされたアドレスを返してくれるようです.
int *p;
p = malloc(sizeof(int));
*p = 1;
それでは,リスト3のコードではどうでしょうか? この場合も,コンパイラはCPUのアラインメント制約を知っているため,構造体のメンバへのアクセスがunaligned accessにならないように上手に配置してくれます.testとtest.bのアドレスも表示してみましょう(リスト4).
1: #include <stdio.h>
2:
3: struct test_t {
4: char a;
5: int b;
6: };
7:
8: struct test_t test = {0x10, 0x20};
9:
10: int main()
11: {
12: int val;
13:
14: val = test.b;
15: printf("%08x\n", val);
16:
17: return 0;
18: }
1: #include <stdio.h>
2:
3: struct test_t {
4: char a;
5: int b;
6: };
7:
8: struct test_t test = {0x10, 0x20};
9:
10: int main()
11: {
12: int val;
13:
14: val = test.b;
15: printf("%08x\n", val);
16: printf("test: %p\n", &test);
17: printf("test.b: %p\n", &test.b);
18:
19: return 0;
20: }
16行目と17行目に,testのアドレスとそのメンバ変数「b」のアドレスを表示するための文を追加しました.実行すると,
$ ./unaligned-struct-offset
00000020
test: 0x80495c0
test.b: 0x80495c4
と表示されました.bのオフセットが4バイトであることが分かります(図1).つまり,aとbの間には3バイトの詰め物があることになります.