主要解读cubemx生成的stm32f103c6tx_flash.ld文件。

链接脚本概要

**  Abstract    : Linker script for STM32F103C6Tx series
**                32Kbytes FLASH and 10Kbytes RAM
**
**                Set heap size, stack size and stack location according to application requirements.
**
**                Set memory bank area and size if external memory is used.
  • STM32F103C6Tx 系列有32 KB 的 FLASH 和 10 KB 的 RAM。
  • 根据应用程序需求设置堆大小、栈大小和栈位置。
  • 如果使用外部存储器,用来设置存储块区域位置和大小。

链接脚本内容

/* Entry Point */
ENTRY(Reset_Handler)

指定程序的入口点(Entry Point):Reset_HandlerReset_Handler在启动汇编中定义。Reset_Handler里调用了c程序入口main

/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);    /* 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 */

RAM存储区域的定义在下面的MEMORY里。ORIGIN表示存储区域的起始地址,LENGTH表示存储区域的长度。
此处定义了栈顶_estack 在RAM的最高地址处,说明了栈是从RAM的最高地址往下生成的,堆是从RAM的最低地址处往上生长。
_Min_Heap_Size_Min_Stack_Size 定义了堆和栈的最小大小。

/* Specify the memory areas */
MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 10K
FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 32K
}

定义存储区域RAMFLASH的位置和大小。

/* Define output sections */
SECTIONS
{
  ...
}

SECTIONS用于定义程序的段布局,它告诉链接器如何将输入文件中的段映射到输出文件的段,并指定它们在存储器中的位置。段定义顺序直接决定了这些段在存储器中的排列顺序。

/* The startup code goes first into FLASH */
 .isr_vector ://输出的.isr_vector段 
 {
   . = ALIGN(4);
   KEEP(*(.isr_vector)) /* Startup code */
   . = ALIGN(4);
 } >FLASH

. = AKIGN(4)确保当前地址对齐到 4 字节边界,对齐操作是为了满足处理器的要求。*表示匹配所有输入文件,(.isr_vector)表示匹配所有名为isr_vector的段,KEEP是告诉链接器保留这些段,即使它们未被显式引用。>FLASH将· isr_vector 段放置到 Flash 存储器中。
KEEP(*(.isr_vector))是指保留所有输入文件的.isr_vector段。

/* The program code and other data goes into FLASH */
.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)
	KEEP (*(.init))
	KEEP (*(.fini))
	. = ALIGN(4);
	_etext = .;        /* define a global symbols at end of code */
 } >FLASH

定义一个名为 .text 的输出段,将该段的内容映射到 Flash 存储器中。将所有输入文件中的 .text段相关段(如 .glue_7.eh_frame等,这些是由编译器产生的段)合并到.text输出段中。保留 .init.fini 段,避免被优化掉,.init .fini 段是由编译器和链接器生成的特殊段,用于存放程序启动时的初始化代码(.init)和程序退出时的清理代码(.fini)定义 _etext 符号,表示 .text 段的结束地址。

/* Constant data goes into FLASH */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

.rodata 段将程序的只读数据(constants、strings 等)放置到 Flash 存储器中。

 .ARM.extab : { 
 	*(.ARM.extab* .gnu.linkonce.armextab.*) 
 } >FLASH
 
 .ARM : {
   __exidx_start = .;
   *(.ARM.exidx*)
   __exidx_end = .;
 } >FLASH

.ARM.extab段包含异常表(Exception Table)的相关信息。这些信息主要用于支持 C++ 异常处理(如 try-catch 块)。.gnu.linkonce.armextab.*是编译器生成的一种特殊段,用于避免重复定义。
.ARM.exidx段包含异常索引表(Exception Index Table),用于支持 C++ 异常处理。异常索引表记录了函数的异常处理信息,例如栈展开(stack unwinding)所需的元数据。__exidx_start__exidx_end 是全局符号,通常被运行时库使用,以定位异常索引表的范围。

.preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH

.preinit_array用于存放程序启动时需要执行的 预初始化函数 的指针数组。这些函数会在 .init 段之前执行,通常用于非常早期的初始化任务(如设置硬件环境)。
PROVIDE_HIDDEN 是 GNU 链接器的一个伪指令,用于定义一个局部可见的符号(即不会被导出到外部模块)。

.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

.init_array.fini_array 段的部分,用于存放程序启动和退出时需要执行的初始化和清理函数的指针数组。
编译器会为每个初始化函数生成一个单独的 .init_array. 段,其中 是优先级编号。SORT 确保这些段按优先级顺序排列,从而保证初始化函数按正确的顺序执行。

/* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .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 section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _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

_sidata表示 .data 段在 Flash 中的加载地址。
,data{...}>RAM AT> FLASH表示在FLASH(加载地址)加载,在RAM(运行时地址)运行。
定义了.data和.bss的起始结束地址,启动代码会用到。

  /* 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

User_heap_stack段,检查ram是否有剩余。·end· 和 ·_end· 是标准符号,表示可用堆空间的起始地址。

  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

/DISCARD/ 是一个特殊段,用于指定哪些输入文件或段需要被丢弃。libc.alibm.a libgcc.a通常包含许多未使用的函数或数据。libc.a 是 C 标准库的静态版本,包含许多常用的函数(如 printf、malloc 等)。libm.a 是数学库的静态版本,包含数学运算相关的函数(如 sin、cos、sqrt 等)。libgcc.a 是 GCC 编译器提供的运行时支持库,包含一些低级操作(如整数除法、浮点运算支持等)。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐