ヒープ調査メモ
arduino でヒープを使いたくなったので調べてみた結果をメモっておきます.
ヒープを使うには
そもそも malloc 的な関数は使えるのかね? と思ってしらべたらありました.
http://www11.ocn.ne.jp/~akibow/avr-libc-user-manual-1.4.3/malloc.html を読むと以下のような構造になっていることがわかりました.
- ヒープの先頭は __malloc_heap_start から
- ヒープの末尾は __malloc_heap_end が 0 の場合, スタックトップアドレスに 32byte 足したところまで
- __malloc_heap_end で任意の末尾を設定することも可能. 詳細はhttp://www11.ocn.ne.jp/~akibow/avr-libc-user-manual-1.4.3/malloc.htmlに記載の通り.
- スタックトップアドレスはマクロ SP で参照できます. くわしくは arduino-0013\hardware\tools\avr\avr\include\avr\common.h とデータシートを見てください.
以下のスケッチを使って確認してみました.(arduino は arduino-0013 with atmega328 の状態です)
#include <stdlib.h> void setup() { Serial.begin(9600); Serial.println((int)__malloc_heap_start, HEX); Serial.println((int)__malloc_heap_end, HEX); Serial.println((int)__malloc_margin, HEX); Serial.println((int)SP, HEX); } void loop() {}
出力結果はこんなんなりました.
1A2 0 20 8F9
ヒープの構造は http://www11.ocn.ne.jp/~akibow/avr-libc-user-manual-1.4.3/malloc.html にある以下の図の通りになってるので,
メモリ割り当て状況をしらべるには
avr-objdump と avr-nm を使ってしらべてみます.
arduino IDE が以下にインストールされている状況とします.
c:\arduino-0013\hardware\tools\avr\bin
まずはパスを通します.
set PATH=%PATH%;c:\arduino-0013\hardware\tools\avr\bin
スケッチを保存してあるフォルダ*3へ移動してセクション情報を出力します.
cd c:\sketch_090218a/applet avr-objdump -h sketch_090228a.elf > list.lst
出力されるファイルはこんな感じになりました.
sketch_090228a.elf: file format elf32-avr Sections: Idx Name Size VMA LMA File off Algn 0 .data 0000000c 00800100 00000730 000007a4 2**0 CONTENTS, ALLOC, LOAD, DATA 1 .text 00000730 00000000 00000000 00000074 2**1 CONTENTS, ALLOC, LOAD, READONLY, CODE 2 .bss 00000096 0080010c 0000073c 000007b0 2**0 ALLOC 3 .debug_aranges 000002e8 00000000 00000000 000007b0 2**0 CONTENTS, READONLY, DEBUGGING 4 .debug_pubnames 000005e8 00000000 00000000 00000a98 2**0 CONTENTS, READONLY, DEBUGGING 5 .debug_info 00001e7c 00000000 00000000 00001080 2**0 CONTENTS, READONLY, DEBUGGING 6 .debug_abbrev 00000bb4 00000000 00000000 00002efc 2**0 CONTENTS, READONLY, DEBUGGING 7 .debug_line 000018c5 00000000 00000000 00003ab0 2**0 CONTENTS, READONLY, DEBUGGING 8 .debug_frame 00000470 00000000 00000000 00005378 2**2 CONTENTS, READONLY, DEBUGGING 9 .debug_str 000009e4 00000000 00000000 000057e8 2**0 CONTENTS, READONLY, DEBUGGING 10 .debug_loc 000010bc 00000000 00000000 000061cc 2**0 CONTENTS, READONLY, DEBUGGING 11 .debug_ranges 00000290 00000000 00000000 00007288 2**0 CONTENTS, READONLY, DEBUGGING
http://www11.ocn.ne.jp/~akibow/avr-libc-user-manual-1.4.3/mem_sections.html をしらべたところによると, セクションには以下の制限があるぽいです.*4
- .text (コード)は上位 16bit を 0x0000 にしなければいけない.
- .data, .bss (データ)は上位 16bit を 0x0080 にしなければいけない.
avr-objdump の出力結果のよみかたはこんな感じです.
セクション | 意味 |
---|---|
.text | アドレス 0x0000 から 1840 バイト割り当て済み |
.data | アドレス 0x0100 から 12 バイト割り当て済み |
.bss | アドレス 0x010C から 150 バイト割り当て済み |
atmega328 の データシート の 5.3 SRAM Data Memory にある以下の図的にもあってるようです.
つづきまして、avr-nm をつかってヒープ関連のシンボルを見てみたいと思います.
こんな感じでシンボル一覧を出力すると
avr-nm -n -C sketch_090228a.elf > syms.lst
こんな結果がでてきます
00000000 W __heap_end 00000000 a __tmp_reg__ 00000000 a __tmp_reg__ 00000000 a __tmp_reg__ 00000000 a __tmp_reg__ 00000000 a __tmp_reg__ 00000000 a __tmp_reg__ 00000000 a __tmp_reg__ 00000000 a __tmp_reg__ 〜〜〜長いので中略〜〜〜 00000730 T _etext 0000073c A __data_load_end 000008ff W __stack 00800100 D __data_start 00800100 D __malloc_margin 00800102 D __malloc_heap_start 00800104 D __malloc_heap_end 00800106 V vtable for HardwareSerial 0080010c B Serial 0080010c B __bss_start 0080010c D __data_end 0080010c D _edata 0080010e b intFunc 00800112 B timer0_overflow_count 00800116 B timer0_clock_cycles 0080011a B timer0_millis 0080011e B rx_buffer_head 00800120 B rx_buffer_tail 00800122 B rx_buffer 008001a2 B __bss_end 008001a2 N __heap_start 008001a2 N _end 00810000 N __eeprom_end
上記 avr-nm の結果とスケッチの実行結果を比較してみると,
と正しいようです.
また, http://www11.ocn.ne.jp/~akibow/avr-libc-user-manual-1.4.3/malloc.html に記載があるとおり, __heap_start は .bss セクションの末尾に配置されていることが見てとれます. なので .data, .bss のサイズによって __heap_start のアドレスが決定することになるようです.
まとめ
なんだかとりとめない内容で申し訳ありませんが, まとめると以下 3 点となります.