ここでは、例としてSTM32F103x8Bのリンカスクリプトを作ることを考えます。 右の図がSTM32F103x8Bのメモリマップです。メモリは8つのブロックに分けられ、 外部バスを持つデバイスでは、3〜4の空きブロックに外部メモリを割り当てることが可能です。
リンカスクリプトは、STマイクロのサンプルプログラムに同梱されている
STM32F10x_StdPeriph_Lib_V3.3.0 Project\STM32F10x_StdPeriph_Template\RIDE\stm32f10x_flash_extsram.ld
を必要に応じて修正して使っています。入出力セクションの関係を表にしてみました。 MEMORY定義とARM.extab,ARM.exidxを修正・追加しています。 ARM.extab,ARM.exidxはnewlibを使うときに必要となるセクションで、 例外処理のために使われているらしいです。 なお、アドレス欄の赤文字は開始アドレス、 青文字は終了アドレスを表しています。
memory | output | input | address | information |
---|---|---|---|---|
Flash | .isr_vector | .isr_vector | 0x08000000 | 割り込みベクタ領域 |
.text | .text | コード領域 | ||
.text.* | その他のコード領域 | |||
.rodata | 定数データ | |||
.rodata.* | その他の定数データ | |||
.glue_7 | ARMインターワーキング用? | |||
.glue_7.* | - | |||
.ARM.extab | .ARM.extab* | 例外テーブル(newlib) | ||
.gnu.linkonce.armextab.* | ||||
.ARM.exidx | .ARM.exidx* |
__exidx_start __exidx_end, _etext |
例外インデックス(newlib) | |
.gnu.linkonce.armexidx.* | ||||
_sidata | .dataの初期値 | |||
RAM | .data | .data |
0x20000000, _sdata _edata | 初期化子を持つ変数 |
.data.* | - | |||
.bss | .bss |
_sbss, _bss_start _ebss, __bss_end | 初期化子を持たない変数 | |
COMMON | コモンシンボル。 | |||
._usrstack | _susrstack _eusrstack |
スタック予約領域。_Minimum_Stack_Sizeが確保できなくなるとリンカエラーが出る。 | ||
0x200007ff, _estack | スタックの底 |
以下、リンカスクリプト本体です。デバッグ関連のセクションについては省略しています。 デバッガ関連については、おいおい調査したいと思います。
/* デフォルトのスタックサイズ */ __Stack_Size = 1024 ; /* _Stack_Size の弱い定義(プログラムで上書き可能) */ PROVIDE ( _Stack_Size = __Stack_Size ) ; /* スタックの開始アドレス */ __Stack_Init = _estack - __Stack_Size ; /* _Stack_Init の弱い定義 */ PROVIDE ( _Stack_Init = __Stack_Init ) ; /* スタックサイズが以下を下回ったときにリンカエラーを出すようにする */ _Minimum_Stack_Size = 0x100 ; /* Flash領域とRAM領域を定義します(以下はSTM32F10x用) */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20k FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64k } /* スタックの底のアドレス(RAM領域の終端)を _estack に設定 */ _estack = 0x20000000 + 20k; /* プログラムセクション定義 */ SECTIONS { /* Cortexデバイス用スタートアップ、割り込みベクタのセクション */ .isr_vector : { . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); } >FLASH /* プログラムセクション */ .text : { . = ALIGN(4); *(.text) /* コードセクション */ *(.text.*) *(.rodata) /* 定数データ */ *(.rodata*) *(.glue_7) /* インターワーキング用? */ *(.glue_7t) . = ALIGN(4); } >FLASH /* 標準ライブラリで使用するセクション */ .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH __exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >FLASH __exidx_end = .; /* コードセクションの終端、.dataの初期化データ領域の開始位置 */ _etext = .; _sidata = _etext; /* 初期化データを持つ変数領域 */ /* スタートアップ内で初期化データがコピーされます */ .data : AT ( _sidata ) { . = ALIGN(4); _sdata = . ; /* スタートアップ内で参照 */ *(.data) *(.data.*) . = ALIGN(4); _edata = . ; /* スタートアップ内で参照 */ } >RAM /* 初期化子を持たない変数領域 */ .bss : { . = ALIGN(4); _sbss = .; /* スタートアップ内で参照 */ __bss_start__ = .; *(.bss) *(COMMON) . = ALIGN(4); _ebss = . ; /* スタートアップ内で参照 */ __bss_end__ = . ; } >RAM PROVIDE ( end = _ebss ); PROVIDE ( _end = _ebss ); /* 残りスタック領域 */ /* MinStackSizeより小さい場合はリンカエラーを出します */ ._usrstack : { . = ALIGN(4); _susrstack = . ; . = . + _Minimum_Stack_Size ; . = ALIGN(4); _eusrstack = . ; } >RAM /* remove the debugging information from the standard libraries */ DISCARD : { libc.a ( * ) libm.a ( * ) libgcc.a ( * ) } }