ここでは、例として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 ( * )
}
}