AVR Libc Home Page | ![]() |
AVR Libc Development Pages | ||
Main Page | FAQ | Library Reference | Additional Documentation | Example Projects |
以下は利用できるいろいろな "Section" について解説しています。
.text セクションはプログラムを構成する機械語命令を含んでいます。このセクションは .initN と .finiN のセクションに分けられています。
UNIXの風土から来たavr-size
プログラム (binutilsの一部)は、.textに追加される.data
初期化領域について考慮していません。そのため、最終的にフラッシュメモリの占有す量を知るには、.text
と .data(.bssは不要) 両方を加え合わせなければなりません。また、あらかじめ確保されたSRAMは.data
と.bssの合計になります。
このセクションはあなたの書いたコードで宣言された静的データを表します。下記のようなものは最終的に .data 内に納められます。
char err_str[] = "Your program has died a horrible death!"; struct point pt = { 1, 1 };
リンカに.data セクション開始SRAMアドレスを知らせてやることが可能です。これはavr-gccのリンクコマンドのオプションに-Wl,-Tdata,addr
を加えることで可能です。addr は0x80 0000を実際のSRAMアドレスに加える必要があります。これによってリンカはこれがSRAM内のメモリスペースであることを知ることができます。.data
セクションが0x1100から始まるよう指定したければ、0x801100をリンカへのアドレス値として渡してやります。(offsetについてはここで説明しています )
※アドレスは23bitで、最上位はバンク番号とでも考えればいい?
malloc()
をアプリケーション内で使用している場合は(ライブラリ内で使用されている場合も含む)、さらに追加の調整 が必要です。
初期化されていない、global またはstatic 変数は、.bss セクションに納められます。
ここはeeprom内変数が保存される場所です。
このセクションは .bss セクションの一部です。下記のように定義される変数が .noinit に納められます。
int foo __attribute__ ((section (".noinit")));
この定義による変数は、通常の .bss データと異なり、スタートアップ時 0 で初期化されません。
初期化されない変数だけが .noinit セクションに置かれます。下記のようなコードはエラーをおこします。
int bar __attribute__ ((section (".noinit"))) = 0xaa;
リンカに明示的に .noinit セクションが置かれるかをavr-gccコマンドラインのリンクコマンドのオプションに -Wl,--section-start=.noinit=addr
を加えることで指定できます。以下の例では、.noinit
セクションを SRAMの0x2000に置くことを指定しています。
$ avr-gcc ... -Wl,--section-start=.noinit=0x802000 ...
代わりに、この辺を自動化するために、あなた自身のリンカスクリプトを書くこともできます。 [FIXME: リンカスクリプトを書くための例題かリファレンスを募集中.]
このセクションはリセットから main()
が始まるまでの間のスタートアップコードを表します。これらは.text sectionの一部です。
これらのセクションの目的はプログラム内でのコードの置き場所をより特定できるようにするためです。
.initN section
コードは関数としてコールしたり、そこにジャンプしたりすることはできません。
.initN セクションは0〜9の順番で実行されます。
__init()
と結びつけられている。ユーザーが __init()
を定義すれば、リセット後すぐに実行されます。
__zero_reg__ (r1)
をクリアしています。
.init4
は .data
の内容をフラッシュからSRAMへコピーするコードを納めています。.bss
セクションをゼロクリアするコードを libgcc,a
からロードします。
これらのセクションは main()
からの return、または exit() 関数コール後に実行されるものです。これらすべては
.text sectionの一部です。
.finiN セクションは9番から0版にかけて実行されます。
#include <avr/io.h> .section .init1,"ax",@progbits ldi r0, 0xff out _SFR_IO_ADDR(PORTB), r0 out _SFR_IO_ADDR(DDRB), r0
,"ax",@progbits
はアセンブラにセクションが allocatable("a)で、実行可能("x")で、データを含む("@progbits")でであることを伝えます。.section
使用法の詳しい情報については gas user manualをご覧ください。
#include <avr/io.h> void my_init_portb (void) __attribute__ ((naked)) \ __attribute__ ((section (".init3"))); void my_init_portb (void) { PORTB = 0xff; DDRB = 0xff; }
.init3
はこの例では__zero_reg__
はすでに (.init2で)
初期化済みだと保証されます。コンパイラで生成されるコードは
__zero_reg__
が 0 であると盲目的に依存してもかまいません。※このコードで__zero_reg__
を使う理由がよく分からない・・・以下のようなコードになるし。0000001e <my_init_portb>: 1e: 8f ef ldi r24, 0xFF ; 255 20: 88 bb out 0x18, r24 ; 24 22: 87 bb out 0x17, r24 ; 23※PORTB=0x00; DDRB=0x00;
の間違いかと思われます。こうすると以下のように__zero_reg__
を使ってくれます。0000001e <my_init_portb>: 1e: 18 ba out 0x18, r1 ; 24 20: 17 ba out 0x17, r1 ; 23