プログラムはNativeで実行
さて、気を取り直して先ほどのList1のLチカを実行。Pin 13とGNDの間にLEDを繋いで動作させてみた。Sketch Sizeは49,046 Bytesで全体の18%(最大262,144Bytes)となる。内部はスクリプトが色々動いているようで、Arduino IDEのステータス欄に色々動作状態が出てくる(Photo18)。
で、肝心の動作は? というと、最初ACを繋いだ状態だとLEDが微妙に点灯しているだけ(Photo19)だが、Sketchをロードするとちゃんと1秒間隔で点滅を繰り返す(Photo20)。で、USBケーブルを抜いても問題なく動作は継続する(Photo21)。問題はここで一度ACアダプタを抜いて、再度ACアダプタを接続した場合。Arduinoの場合だと、SketchはFlash Memoryに格納されるから、電源を入れればPower on bootでFlashからSketchが読み出され、再び勝手に実行を始める。ところがGalileoの場合はPhoto19の状態に戻ってしまうのだ。つまりGalileoのArduino互換モードでは、SketchはFlash MemoryではなくSRAMに格納されるようだ。先にSketchの最大サイズが256KBと書いたが、おそらくSRAMの半分をSystemで、残りをSketchで利用しているのだろう。
Photo19: この状態だとI2C経由のGPIOがまだ初期化がなされておらず、Hi-Z状態になっているのではないかと思われる。この状態における明るさ(≒Hi-Zにおいて流れる電圧)はArduinoよりも間違いなく高いようだ。 |
Photo20: 輝度はこんなもんだろう。 |
このあたりでArduino互換とは言え、使い方にちょっと制約が出てくる気がするが、それはさておきファイルサイズの話。同じSketchをArduino UNO用にビルドすると1,076Bytesである。アーキテクチャが違うとはいえ、何でここまでファイルサイズが違うのか? ということで、ちょっとバイナリを確認してみることにした。
Galileo向けのArduino IDEでは最終的にELFフォーマットでバイナリを生成するようだ。先のPhoto18にもちょっと出てくるが、Galileo用Arduino IDEは自動でユーザーディレクトリの下の方(詳しくはPhoto18を参照)にディレクトリを作り、その中にファイルを生成する(Photo22)。で、この中にある.elfファイルがGalileoにダウンロードされるものの様だ。そこでobjdumpを使って中身をちょっと確認してみた。まずobjdump -xでヘッダ情報を出したのがList 2である。ファイルフォーマットはelf32-i386なので、つまりこのSketchはGalileoでNativeで実行できるようになっていると考えられる。
■ List 2
objdump -x C:\Users\kuma\Desktop\Galileo_001.cpp.elf
C:\Users\kuma\Desktop\Galileo_001.cpp.elf: file format elf32-i386
C:\Users\kuma\Desktop\Galileo_001.cpp.elf
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x08048e64
Program Header:
PHDR off 0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2
filesz 0x00000100 memsz 0x00000100 flags r-x
INTERP off 0x00000134 vaddr 0x08048134 paddr 0x08048134 align 2**0
filesz 0x00000014 memsz 0x00000014 flags r--
LOAD off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12
filesz 0x00004e28 memsz 0x00004e28 flags r-x
LOAD off 0x00005000 vaddr 0x0804d000 paddr 0x0804d000 align 2**12
filesz 0x00006b20 memsz 0x0000729c flags rw-
DYNAMIC off 0x00005018 vaddr 0x0804d018 paddr 0x0804d018 align 2**2
filesz 0x000000e8 memsz 0x000000e8 flags rw-
NOTE off 0x00000148 vaddr 0x08048148 paddr 0x08048148 align 2**2
filesz 0x00000024 memsz 0x00000024 flags r--
EH_FRAME off 0x00004448 vaddr 0x0804c448 paddr 0x0804c448 align 2**2
filesz 0x000001a4 memsz 0x000001a4 flags r--
STACK off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2
filesz 0x00000000 memsz 0x00000000 flags rw-
Dynamic Section:
NEEDED libpthread.so.0
NEEDED libstdc++.so.6
NEEDED libm.so.0
NEEDED libgcc_s.so.1
NEEDED libc.so.0
INIT 0x080489e0
FINI 0x0804b32c
GNU_HASH 0x0804816c
STRTAB 0x08048510
SYMTAB 0x080481b0
STRSZ 0x000002aa
SYMENT 0x00000010
DEBUG 0x00000000
PLTGOT 0x0804d100
PLTRELSZ 0x00000148
PLTREL 0x00000011
JMPREL 0x08048898
REL 0x08048878
RELSZ 0x00000020
RELENT 0x00000008
VERNEED 0x08048828
VERNEEDNUM 0x00000002
VERSYM 0x080487ba
Version References:
required from libstdc++.so.6:
0x056bafd3 0x00 04 CXXABI_1.3
0x08922974 0x00 03 GLIBCXX_3.4
required from libgcc_s.so.1:
0x0d696910 0x00 02 GLIBC_2.0
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 00000014 08048134 08048134 00000134 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.gnu.build-id 00000024 08048148 08048148 00000148 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .gnu.hash 00000044 0804816c 0804816c 0000016c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .dynsym 00000360 080481b0 080481b0 000001b0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .dynstr 000002aa 08048510 08048510 00000510 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .gnu.version 0000006c 080487ba 080487ba 000007ba 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .gnu.version_r 00000050 08048828 08048828 00000828 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .rel.dyn 00000020 08048878 08048878 00000878 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .rel.plt 00000148 08048898 08048898 00000898 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .init 0000001c 080489e0 080489e0 000009e0 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
10 .plt 000002a0 08048a00 08048a00 00000a00 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
11 .text 0000268c 08048ca0 08048ca0 00000ca0 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .fini 00000017 0804b32c 0804b32c 0000332c 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .rodata 00001100 0804b348 0804b348 00003348 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
14 .eh_frame_hdr 000001a4 0804c448 0804c448 00004448 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
15 .eh_frame 0000083c 0804c5ec 0804c5ec 000045ec 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
16 .ctors 0000000c 0804d000 0804d000 00005000 2**2
CONTENTS, ALLOC, LOAD, DATA
17 .dtors 00000008 0804d00c 0804d00c 0000500c 2**2
CONTENTS, ALLOC, LOAD, DATA
18 .jcr 00000004 0804d014 0804d014 00005014 2**2
CONTENTS, ALLOC, LOAD, DATA
19 .dynamic 000000e8 0804d018 0804d018 00005018 2**2
CONTENTS, ALLOC, LOAD, DATA
20 .got.plt 000000b0 0804d100 0804d100 00005100 2**2
CONTENTS, ALLOC, LOAD, DATA
21 .data 00006970 0804d1b0 0804d1b0 000051b0 2**2
CONTENTS, ALLOC, LOAD, DATA
22 .bss 0000077c 08053b20 08053b20 0000bb20 2**5
ALLOC
23 .comment 00000011 00000000 00000000 0000bb20 2**0
CONTENTS, READONLY
SYMBOL TABLE:
no symbols
んではobjdump -dでディスアセンブルするとどうなるか、をリスト全部掲載すると長すぎるので抜粋をList 3に。.initはもうファームウェアの初期化ルーチンを呼んでるだけだし、.pltは処理テーブルがひたすら並んでいるだけである。で、こまごましたものは.textに全部突っ込んであるが、明らかに今回の処理と無関係な関数のディスパッチルーチンまで含まれており、このあたりが無駄に突っ込まれている結果としてファイルサイズはかなり大きくなっていると考えられる(ちなみにobjdumpで -Sオプションをつけてもソースは表示されなかったので、g++でデバッグオプションは付加されていない模様)。
■ List 3
objdump -d C:\Users\kuma\Desktop\Galileo_001.cpp.elf
C:\Users\kuma\Desktop\Galileo_001.cpp.elf: file format elf32-i386
Disassembly of section .init:
080489e0 <_init>:
80489e0: 55 push %ebp
80489e1: 89 e5 mov %esp,%ebp
80489e3: 53 push %ebx
80489e4: e8 9d 04 00 00 call 8048e86 <strcpy@plt+0x1f6>
80489e9: 81 c3 17 47 00 00 add $0x4717,%ebx
80489ef: e8 56 05 00 00 call 8048f4a <strcpy@plt+0x2ba>
80489f4: e8 17 29 00 00 call 804b310 <strcpy@plt+0x2680>
80489f9: 5b pop %ebx
80489fa: 5d pop %ebp
80489fb: c3 ret
Disassembly of section .plt:
08048a00 <__deregister_frame_info@plt-0x10>:
8048a00: ff 35 04 d1 04 08 pushl 0x804d104
8048a06: ff 25 08 d1 04 08 jmp *0x804d108
8048a0c: 00 00 add %al,(%eax)
...
08048a10 <__deregister_frame_info@plt>:
8048a10: ff 25 0c d1 04 08 jmp *0x804d10c
8048a16: 68 00 00 00 00 push $0x0
8048a1b: e9 e0 ff ff ff jmp 8048a00 <_init+0x20>
08048a20 <rewind@plt>:
8048a20: ff 25 10 d1 04 08 jmp *0x804d110
8048a26: 68 08 00 00 00 push $0x8
8048a2b: e9 d0 ff ff ff jmp 8048a00 <_init+0x20>
08048a30 <__errno_location@plt>:
8048a30: ff 25 14 d1 04 08 jmp *0x804d114
8048a36: 68 10 00 00 00 push $0x10
8048a3b: e9 c0 ff ff ff jmp 8048a00 <_init+0x20>
08048a40 <open@plt>:
8048a40: ff 25 18 d1 04 08 jmp *0x804d118
8048a46: 68 18 00 00 00 push $0x18
8048a4b: e9 b0 ff ff ff jmp 8048a00 <_init+0x20>
08048a50 <fwrite@plt>:
8048a50: ff 25 1c d1 04 08 jmp *0x804d11c
8048a56: 68 20 00 00 00 push $0x20
8048a5b: e9 a0 ff ff ff jmp 8048a00 <_init+0x20>
08048a60 <usleep@plt>:
8048a60: ff 25 20 d1 04 08 jmp *0x804d120
8048a66: 68 28 00 00 00 push $0x28
8048a6b: e9 90 ff ff ff jmp 8048a00 <_init+0x20>
(中略)
08048c60 <printf@plt>:
8048c60: ff 25 a0 d1 04 08 jmp *0x804d1a0
8048c66: 68 28 01 00 00 push $0x128
8048c6b: e9 90 fd ff ff jmp 8048a00 <_init+0x20>
08048c70 <puts@plt>:
8048c70: ff 25 a4 d1 04 08 jmp *0x804d1a4
8048c76: 68 30 01 00 00 push $0x130
8048c7b: e9 80 fd ff ff jmp 8048a00 <_init+0x20>
08048c80 <pipe2@plt>:
8048c80: ff 25 a8 d1 04 08 jmp *0x804d1a8
8048c86: 68 38 01 00 00 push $0x138
8048c8b: e9 70 fd ff ff jmp 8048a00 <_init+0x20>
08048c90 <strcpy@plt>:
8048c90: ff 25 ac d1 04 08 jmp *0x804d1ac
8048c96: 68 40 01 00 00 push $0x140
8048c9b: e9 60 fd ff ff jmp 8048a00 <_init+0x20>
Disassembly of section .text:
08048ca0 <.text>:
8048ca0: 8d 4c 24 04 lea 0x4(%esp),%ecx
8048ca4: 83 e4 f0 and $0xfffffff0,%esp
8048ca7: ff 71 fc pushl -0x4(%ecx)
8048caa: 55 push %ebp
8048cab: 89 e5 mov %esp,%ebp
8048cad: 56 push %esi
8048cae: 53 push %ebx
8048caf: 51 push %ecx
8048cb0: 83 ec 10 sub $0x10,%esp
8048cb3: 8b 31 mov (%ecx),%esi
8048cb5: 8b 59 04 mov 0x4(%ecx),%ebx
8048cb8: ff 35 20 3b 05 08 pushl 0x8053b20
8048cbe: 68 c6 c2 04 08 push $0x804c2c6
8048cc3: 68 0c b6 04 08 push $0x804b60c
8048cc8: e8 83 fe ff ff call 8048b50 <freopen@plt>
8048ccd: 83 c4 10 add $0x10,%esp
8048cd0: a3 20 3b 05 08 mov %eax,0x8053b20
8048cd5: 85 c0 test %eax,%eax
8048cd7: 75 14 jne 8048ced <strcpy@plt+0x5d>
8048cd9: 51 push %ecx
8048cda: 51 push %ecx
8048cdb: ff 35 6c 3b 05 08 pushl 0x8053b6c
8048ce1: 68 19 b6 04 08 push $0x804b619
8048ce6: e8 f5 fe ff ff call 8048be0 <fputs@plt>
8048ceb: eb 3a jmp 8048d27 <strcpy@plt+0x97>
8048ced: 83 ec 0c sub $0xc,%esp
8048cf0: 50 push %eax
8048cf1: e8 fa fe ff ff call 8048bf0 <fflush@plt>
8048cf6: 83 c4 0c add $0xc,%esp
8048cf9: ff 35 6c 3b 05 08 pushl 0x8053b6c
8048cff: 68 c6 c2 04 08 push $0x804c2c6
8048d04: 68 33 b6 04 08 push $0x804b633
8048d09: e8 42 fe ff ff call 8048b50 <freopen@plt>
8048d0e: 83 c4 10 add $0x10,%esp
8048d11: a3 6c 3b 05 08 mov %eax,0x8053b6c
8048d16: 85 c0 test %eax,%eax
8048d18: 75 19 jne 8048d33 <strcpy@plt+0xa3>
8048d1a: 83 ec 0c sub $0xc,%esp
8048d1d: 68 43 b6 04 08 push $0x804b643
8048d22: e8 49 ff ff ff call 8048c70 <puts@plt>
8048d27: c7 04 24 ff ff ff ff movl $0xffffffff,(%esp)
8048d2e: e8 0d ff ff ff call 8048c40 <exit@plt>
8048d33: 83 ec 0c sub $0xc,%esp
8048d36: 50 push %eax
8048d37: e8 b4 fe ff ff call 8048bf0 <fflush@plt>
8048d3c: 83 c4 10 add $0x10,%esp
8048d3f: 83 fe 02 cmp $0x2,%esi
8048d42: 7e 52 jle 8048d96 <strcpy@plt+0x106>
8048d44: ff 73 08 pushl 0x8(%ebx)
8048d47: ff 73 04 pushl 0x4(%ebx)
8048d4a: ff 33 pushl (%ebx)
8048d4c: 68 70 b6 04 08 push $0x804b670
8048d51: e8 0a ff ff ff call 8048c60 <printf@plt>
8048d56: 5a pop %edx
8048d57: ff 35 20 3b 05 08 pushl 0x8053b20
8048d5d: e8 8e fe ff ff call 8048bf0 <fflush@plt>
8048d62: 59 pop %ecx
8048d63: 58 pop %eax
8048d64: 6a 00 push $0x0
8048d66: 6a 01 push $0x1
8048d68: e8 22 20 00 00 call 804ad8f <strcpy@plt+0x20ff>
8048d6d: c7 04 24 01 00 00 00 movl $0x1,(%esp)
8048d74: e8 f5 20 00 00 call 804ae6e <strcpy@plt+0x21de>
8048d79: e8 db 12 00 00 call 804a059 <strcpy@plt+0x13c9>
8048d7e: 58 pop %eax
8048d7f: 5a pop %edx
8048d80: 53 push %ebx
8048d81: 56 push %esi
8048d82: e8 b3 0c 00 00 call 8049a3a <strcpy@plt+0xdaa>
8048d87: e8 06 02 00 00 call 8048f92 <strcpy@plt+0x302>
8048d8c: 83 c4 10 add $0x10,%esp
8048d8f: e8 12 02 00 00 call 8048fa6 <strcpy@plt+0x316>
8048d94: eb f9 jmp 8048d8f <strcpy@plt+0xff>
8048d96: 50 push %eax
8048d97: 50 push %eax
8048d98: ff 35 6c 3b 05 08 pushl 0x8053b6c
8048d9e: 68 5c b6 04 08 push $0x804b65c
8048da3: e8 38 fe ff ff call 8048be0 <fputs@plt>
8048da8: 8d 65 f4 lea -0xc(%ebp),%esp
8048dab: 83 c8 ff or $0xffffffff,%eax
8048dae: 59 pop %ecx
8048daf: 5b pop %ebx
8048db0: 5e pop %esi
8048db1: 5d pop %ebp
8048db2: 8d 61 fc lea -0x4(%ecx),%esp
8048db5: c3 ret
(中略)
804b2d2: 55 push %ebp
804b2d3: 89 e5 mov %esp,%ebp
804b2d5: 57 push %edi
804b2d6: 56 push %esi
804b2d7: 53 push %ebx
804b2d8: 83 ec 1c sub $0x1c,%esp
804b2db: 31 f6 xor %esi,%esi
804b2dd: 8b 5d 0c mov 0xc(%ebp),%ebx
804b2e0: 8b 45 10 mov 0x10(%ebp),%eax
804b2e3: 01 d8 add %ebx,%eax
804b2e5: 8b 7d 08 mov 0x8(%ebp),%edi
804b2e8: 89 45 e4 mov %eax,-0x1c(%ebp)
804b2eb: eb 11 jmp 804b2fe <strcpy@plt+0x266e>
804b2ed: 0f b6 0b movzbl (%ebx),%ecx
804b2f0: 50 push %eax
804b2f1: 50 push %eax
804b2f2: 8b 07 mov (%edi),%eax
804b2f4: 51 push %ecx
804b2f5: 57 push %edi
804b2f6: 43 inc %ebx
804b2f7: ff 10 call *(%eax)
804b2f9: 83 c4 10 add $0x10,%esp
804b2fc: 01 c6 add %eax,%esi
804b2fe: 3b 5d e4 cmp -0x1c(%ebp),%ebx
804b301: 75 ea jne 804b2ed <strcpy@plt+0x265d>
804b303: 8d 65 f4 lea -0xc(%ebp),%esp
804b306: 89 f0 mov %esi,%eax
804b308: 5b pop %ebx
804b309: 5e pop %esi
804b30a: 5f pop %edi
804b30b: 5d pop %ebp
804b30c: c3 ret
804b30d: 66 90 xchg %ax,%ax
804b30f: 90 nop
804b310: 55 push %ebp
804b311: 89 e5 mov %esp,%ebp
804b313: 53 push %ebx
804b314: bb 04 d0 04 08 mov $0x804d004,%ebx
804b319: 52 push %edx
804b31a: eb 05 jmp 804b321 <strcpy@plt+0x2691>
804b31c: ff d0 call *%eax
804b31e: 83 eb 04 sub $0x4,%ebx
804b321: 8b 03 mov (%ebx),%eax
804b323: 83 f8 ff cmp $0xffffffff,%eax
804b326: 75 f4 jne 804b31c <strcpy@plt+0x268c>
804b328: 58 pop %eax
804b329: 5b pop %ebx
804b32a: 5d pop %ebp
804b32b: c3 ret
Disassembly of section .fini:
0804b32c <_fini>:
804b32c: 55 push %ebp
804b32d: 89 e5 mov %esp,%ebp
804b32f: 53 push %ebx
804b330: e8 51 db ff ff call 8048e86 <strcpy@plt+0x1f6>
804b335: 81 c3 cb 1d 00 00 add $0x1dcb,%ebx
804b33b: e8 ab db ff ff call 8048eeb <strcpy@plt+0x25b>
804b340: 5b pop %ebx
804b341: 5d pop %ebp
804b342: c3 ret
ただし、この結果として性能は猛烈に高い。以前chipKit32を比較したときのSketch(List 4)をそのまま実施してみたところ、
Arduino Uno | 所要時間約44秒 |
---|---|
Galileo | 約1秒未満(一瞬) |
だった(以前Arduino Unoでは約11秒だったので大分遅くなってるのだが、Arduino IDEのバージョンが大分違うので、おそらくこれが影響しているのではないかと思う。ちなみに今回は1.0.5を利用)。これは81億回の足し算を500回繰り返すものだが、性能面では勝負にならないほどGalileoが高速だった。まぁ16MHz駆動の8bit MCUと400MHz駆動のPentium互換CPUで性能が同じでは話にならないので当然ではあるが、とりあえずArduino IDEで記述したSketchは、仮想マシンなどで動くのではない様である。まぁこれはこれで、ループなどでタイミング調整を行っているSketchでは問題が出てくるかもしれないが。
■ List 4
#define REPEAT 90000
void setup()
{
pinMode(13, OUTPUT);
}
void loop()
{
unsigned long lpCnt1,lpCnt2,lpCnt3;
unsigned long num;
delay(1000);
digitalWrite(13, HIGH);
for(lpCnt1=0; lpCnt1<500; lpCnt1++)
{
for(lpCnt2=0; lpCnt2<REPEAT; lpCnt2++)
{
for(lpCnt3=0; lpCnt3<REPEAT; lpCnt3++)
{
num+=lpCnt2+lpCnt3;
}
}
}
if(num) digitalWrite(13, LOW);
else digitalWrite(13, LOW);
while(1);
}