STMicroelectronics の STM32F746NG マイクロコントローラを使用しています。このデバイスは、ARM Cortex-M7 アーキテクチャに基づいています。サンプル プロジェクトのリンカー スクリプトを理解するためにかなりの時間を費やしました。基本的なことは理解できましたが、まだ大部分を把握できていません。それらの部分を理解するのを手伝ってください。
リンカースクリプトの開始
リンカー スクリプトは次のように開始します。
/* Entry Point */
ENTRY(Reset_Handler) /* The function named 'Reset_Handler' is defined */
/* in the 'startup.s' assembly file. */
/* Highest address of the user mode stack */
/* Remember: the stack points downwards */
_estack = 0x20050000; /* End of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* Required amount of heap */
_Min_Stack_Size = 0x400; /* Required amount of stack */
/* --------------------------------------------------------------------*/
/* MEMORY AREAS */
/* --------------------------------------------------------------------*/
MEMORY
{
/* FLASH MEMORY */
/* ------------ */
/* Remember: the flash memory on this device can */
/* get accessed through either the AXIM bus or the */
/* ITCM bus. Accesses on the ITCM bus start at */
/* address 0x0020 0000. Accesses on the AXIM bus */
/* at address 0x0800 0000. */
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
/* FLASH (rx) : ORIGIN = 0x00200000, LENGTH = 1024K */
/* RAM MEMORY */
/* ---------- */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K
}
ベクトル テーブルとプログラム コード
メモリ領域を定義した後、リンカー スクリプトはセクションの定義に進みます。リンカー スクリプトで定義されている最初のセクションはベクター テーブルです。フラッシュ メモリの最初のバイトで終了する必要があります。
/* --------------------------------------------------------------------*/
/* OUTPUT SECTIONS */
/* --------------------------------------------------------------------*/
SECTIONS
{
/****************************/
/* VECTOR TABLE */
/****************************/
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Vector Table */
. = ALIGN(4);
} >FLASH
ベクタ テーブルを挿入したら、次はプログラム コードです。
/****************************/
/* PROGRAM CODE */
/****************************/
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* Glue ARM to Thumb code */
*(.glue_7t) /* Glue Thumb to ARM code */
*(.eh_frame)
/* Note: The function ‘.text.Reset_Handler’ is one of the *(.text*) sections, */
/* such that it gets linked into the output .text section somewhere here. */
/* We can verify the exact spot where the Reset_Handler section is positioned, by */
/* examining the second entry of the vector table. */
/* A test has given the following results:
/* FLASH (rx) : ORIGIN = 0x0800 0000 ==> Reset_Handler = 0x0800 1C91 */
/* FLASH (rx) : ORIGIN = 0x0020 0000 ==> Reset_Handler = 0x0020 1CB9 */
/*
/* In both cases, the Reset_Handler section ends up a few hundred bytes after the */
/* vector table in Flash. But in the first case, the “Reset_Handler” symbol points */
/* to the Reset-code through AXIM-interface, whereas in the latter case it points */
/* to the Reset-code through the ITCM-interface. */
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* Define a global symbol at end of code */
} >FLASH
e_text
リンカー スクリプトは、フラッシュ内のプログラム コードが終了するアドレスを表すグローバル シンボルを定義します。
定数データ
読み取り専用データも最終的にフラッシュ メモリに格納されます (揮発性の RAM に配置しても意味がありません)。リンカー スクリプトは、.rodata
セクションがフラッシュにある必要があることを定義します。
/****************************/
/* CONSTANT DATA */
/****************************/
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
フラッシュの謎のセクション
一定の読み取り専用データの移動先を定義した後、リンカー スクリプトは、いくつかの「謎の」セクションも最終的にフラッシュに格納するように定義します。
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} >FLASH
.ARM :
{
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
それらのセクションが何であるかはわかりません。それでは、これを最初の質問にしましょう。これらのセクションとは何ですか? また、それらはどのオブジェクト ファイルに表示されますか? ご存じのとおり、リンカー スクリプトはいくつかのオブジェクト ファイルをリンクする必要があります。これらの不可解なセクションがどのオブジェクト ファイルに存在するのか、私にはわかりません。
.ARM.extab
.ARM
.preinit_array
.init_array
.fini_array
以上でフラッシュメモリへの割り当ては終了です。リンカー スクリプトは、RAM に配置されるセクションの定義を続行します。
RAM のセクション
.data
との.bss
セクションは私には明らかです。これについての質問はありません。
/****************************/
/* INITIALIZED DATA */
/****************************/
_sidata = LOADADDR(.data);
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/****************************/
/* UNINITIALIZED DATA */
/****************************/
. = ALIGN(4);
.bss :
{
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
リンカー スクリプトは._user_heap_stack
セクションも定義します。
/****************************/
/* USER_HEAP_STACK SECTION */
/****************************/
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
どうやら、このセクションはすぐには使用されません。RAMにスタックとヒープ用の十分なスペースがあるかどうかを確認するためだけに定義されています。そうでない場合 (.
トップ RAM アドレスを超えている場合) は、リンカ エラーがスローされます。
リンカースクリプトの終わり
これがリンカースクリプトの終了方法です。そして正直なところ、私はそれが何をするのか分かりません。これが 2 番目の質問です。次の意味は何ですか?
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
/* END OF LINKERSCRIPT */