CONTEX-M33 LD链接文件解析

ENTRY(Reset_Handler) //定义程序的入口点为Reset_Handler

//定义用户模式堆栈的最高地址为PSRAM起始地址加上其长度,即PSRAM的末尾地址
_estack = ORIGIN(PSRAM) + LENGTH(PSRAM);

_Min_Heap_Size = 0x100000; //定义堆的最小大小为0x100000(1MB)
_Min_Stack_Size = 0x3000; //栈的最小大小为0x3000(12KB)

//定义了目标设备的内存区域及其属性和大小
MEMORY
{
//存放中断向量表(Vector Table),位于ITCM起始地址,1KB固定大小,需0x00000000对齐
VTOR_ITCM (xrw) : ORIGIN = 0x00000000, LENGTH = 1K
//ITCM存放关键执行代码(如中断服务程序),确保快速响应
CODE_ITCM (xrw) : ORIGIN = 0x00000400, LENGTH = 32K-1K
//共享数据区(通常用于核间通信),DTCM首部256字节,低延迟访问
SHARE_DTCM (xrw) : ORIGIN = 0x20000000, LENGTH = 256
//高频访问数据(如堆栈、全局变量),与CPU直连,速度优于SDRAM
DATA_DTCM (xrw) : ORIGIN = 0x20000100, LENGTH = 32K-256
//常规代码,普通SRAM,容量较大但速度较慢
CODE_RAM (xrw) : ORIGIN = 0x20008000, LENGTH = 96K
//常规数据区,普通SRAM,容量较大但速度较慢
DATA_RAM (xrw) : ORIGIN = 0x20020000, LENGTH = 352K-96K
//Bootloader区(只读属性)
BT_FLASH (rx) : ORIGIN = 0x08002000, LENGTH = 248K
//固件存储区(只读属性)
FW_FLASH (rx) : ORIGIN = 0x08040100, LENGTH = 4M-248K-256
//外部伪静态RAM
PSRAM (rw) : ORIGIN = 0x88000000, LENGTH = 8M
}

SECTIONS
{
_siisr_vector = LOADADDR(.isr_vector); //定义符号_siisr_vector,记录.isr_vector段在Flash中的加载地址
.isr_vector : //定义中断向量表(ISR Vector)的存储和加载规则
{
. = ALIGN(4); //强制4字节对齐,避免未对齐访问导致的硬件异常
_sisr_vector = .; //记录段起始地址(符号供启动代码引用),用于计算拷贝范围
KEEP(*(.isr_vector)) /* Startup code */ //强制保留该段(即使未被引用),确保中断向量表不会被链接器优化删除
. = ALIGN(4);
_eisr_vector = .; //记录段结束地址
} >VTOR_ITCM AT> FW_FLASH //>VTOR_ITCM指定段在ITCM中的执行地址,AT> FW_FLASH指定段在Flash中的存储位置

.text : //.text段包含程序的指令代码、初始化和结束代码等,将被放置在FW_FLASH区域
{
. = ALIGN(4); //强制4字节对齐(ARM指令集要求)
//收集所有目标文件的.text段(主程序代码),标准代码段命名规则
*(.text)
//匹配所有以.text开头的段(如编译器生成的子段),兼容不同编译器的命名变体
*(.text*)
//处理ARM/Thumb指令混合编译的胶合代码,Cortex-M支持Thumb-2指令集时需此处理
*(.glue_7)
*(.glue_7t)
//异常处理帧信息(用于C++异常机制),需与.ARM.exidx段配合使用
*(.eh_frame)

//强制保留初始化/终止化代码(即使未被引用),确保启动和退出流程完整
KEEP (*(.init))
KEEP (*(.fini))

. = ALIGN(4);
//定义全局符号_etext标记代码段结束地址,供启动文件或调试工具定位代码边界
_etext = .;
} >FW_FLASH //定义.text段(程序代码段)的存储位置为FW_FLASH区域

.rodata : //.rodata段包含只读数据(如常量、字符串等),将被放置在FW_FLASH区域
{
. = ALIGN(4);
//收集所有目标文件的.rodata段(显式声明的常量),如const修饰的全局变量、字符串常量
*(.rodata)
//匹配所有以.rodata开头的子段(如编译器生成的隐藏常量),兼容不同编译器的命名变体
*(.rodata*)
. = ALIGN(4);
} >FW_FLASH

//.ARM.extab和.ARM段包含异常处理表和异常索引表,将被放置在FW_FLASH区域
//索引表(.ARM.exidx)和元数据(.ARM.extab)是ARM EABI规定的异常处理机制基础
.ARM.extab : { //存储异常处理元数据
. = ALIGN(4);
*(.ARM.extab* .gnu.linkonce.armextab.*) //通配符匹配所有.ARM.extab开头的段及GNU特定段
. = ALIGN(4);
} >FW_FLASH

.ARM : { //生成异常索引表(Exception Index Table),用于快速定位.ARM.extab中的异常处理信息
//__exidx_start/__exidx_end:供启动代码或运行时库确定表范围
//通过索引表加速异常处理时的元数据查找
. = ALIGN(4);
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(4);
} >FW_FLASH

.preinit_array : //管理C/C++程序的极早期初始化函数
{
//PROVIDE_HIDDEN创建隐藏全局符号__preinit_array_start/end标记段边界
//这些符号仅供链接器内部使用,避免污染全局命名空间
//该段函数在.init_array之前执行,用于架构相关的底层初始化
//典型应用包括CPU时钟配置、内存控制器初始化等硬件相关操作
//此段通常由编译器自动生成,用户可通过__attribute__((constructor))扩展其内容
. = ALIGN(4);
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*)) //KEEP指令确保未被引用的.preinit_array*段不被优化删除
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
} >FW_FLASH

.init_array : //管理C++全局对象的构造函数调用顺序,该段内容在main()前由启动代码__libc_init_array调用
{
//与.preinit_array相比,该段执行时机更晚但更接近main()入口
//PROVIDE_HIDDEN创建隐藏符号__init_array_start/end标记段边界
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
//KEEP确保未被引用的初始化函数不被优化删除
KEEP (*(SORT(.init_array.*))) //对子段按名称排序(实现构造函数优先级)
KEEP (*(.init_array*)) //匹配所有初始化函数指针
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
} >FW_FLASH

//管理程序退出时的清理函数调用顺序
//该段函数在main()结束后由__libc_csu_fini调用
//典型应用包括C++全局对象析构和__attribute__((destructor))函数
.fini_array :
{
//PROVIDE_HIDDEN创建隐藏符号__fini_array_start/end标记段边界
//这些符号仅运行时库内部使用,避免全局命名空间污染
. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*))) //按优先级排序子段(数值越小越晚执行)
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
} >FW_FLASH

//_sidata符号标记.data段在Flash中的加载地址(Load Address)
//该符号由启动代码startup.s使用,用于将初始化数据从Flash拷贝到RAM
//LOADADDR()是链接脚本内置函数,获取指定段的加载地址
//.data段包含已初始化的全局/静态变量
//上电后启动代码会:通过_sidata找到Flash中的初始值,将数据拷贝到RAM中的_sdata位置,清零.bss段(未初始化变量)
_sidata = LOADADDR(.data);

.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */ //PSRAM中的起始地址
*(.data) /* .data sections */ //将所有输入文件中名为 .data 的段合并到当前输出段中
*(.data*) /* .data* sections */ //将所有输入文件中以 .data 开头的段合并到当前输出段中
*(.codepsram) /* .codepsram sections */ //将所有输入文件中名为 .codepsram 的段合并到当前输出段中
*(.codepsram*) /* .codepsram* sections */ //将所有输入文件中名为 .codepsram 开头的段合并到当前输出段中
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */

} >PSRAM AT> FW_FLASH //运行在PSRAM但存储在Flash

_sicodeitcm = LOADADDR(.codeitcm); //标记Flash中的加载地址,供启动代码使用
.codeitcm :
{
//_scodeitcm/_ecodeitcm标记ITCM中的运行地址范围
. = ALIGN(4);
_scodeitcm = .;
*(.codeitcm)
//匹配所有ITCM代码段(含子段),需配合__attribute__((section(“.codeitcm”)))声明关键函数
*(.codeitcm*)

. = ALIGN(4);
_ecodeitcm = .;
} >CODE_ITCM AT> FW_FLASH

_sidatadtcm = LOADADDR(._datadtcm);
//用于将关键数据放入DTCM(数据紧耦合存储器)中运行
._datadtcm :
{
. = ALIGN(4);
_sdatadtcm = .;
*(._datadtcm)
//匹配所有DTCM数据段(含子段),需配合__attribute__((section(“._datadtcm”)))声明关键变量
*(._datadtcm*)

. = ALIGN(4);
_edatadtcm = .;
} >DATA_DTCM AT> FW_FLASH

//用于将关键代码放入RAM执行
_sicoderam = LOADADDR(.coderam); //记录Flash中的原始代码位置
//_scoderam/_ecoderam标记RAM中的运行时地址边界
.coderam :
{
. = ALIGN(4);
_scoderam = .;
//自定义RAM代码段,需配合__attribute__((section(“.coderam”)))声明关键函数
*(.coderam)
*(.coderam*)
//标准RAM函数段
*(.RamFunc)
*(.RamFunc*)
. = ALIGN(4);
_ecoderam = .;
} >CODE_RAM AT> FW_FLASH

_sidataram = LOADADDR(._dataram); //记录Flash中的初始数据位置
._dataram :
{
//_sdataram/_edataram标记RAM中的运行时地址范围
. = ALIGN(4);
_sdataram = .;
*(._dataram)
//匹配所有自定义RAM数据段(含子段),需配合__attribute__((section(“._dataram”)))声明关键变量
*(._dataram*)
. = ALIGN(4);
_edataram = .;
} >DATA_RAM AT> FW_FLASH

. = ALIGN(4);
.bss :
{
//__bss_start__/__bss_end__提供兼容性符号(常见于不同工具链)
_sbss = .;
__bss_start__ = _sbss;
*(.bss)
*(.bss*) //*(.bss*)匹配所有未初始化数据段(含子段)
*(COMMON) //处理未初始化的全局变量(如未赋值的static变量)

. = ALIGN(4);
_ebss = .;
__bss_end__ = _ebss;
} >PSRAM //指定运行时地址在外部PSRAM(伪静态RAM)中

._user_heap_stack : //用户堆栈内存区域,在PSRAM中预留堆和栈空间
{
. = ALIGN(8); //强制8字节对齐(满足ARM Cortex-M架构要求)
PROVIDE ( end = . ); //创建全局符号标记当前地址
PROVIDE ( _end = . );
//_Min_Heap_Size和_Min_Stack_Size需在工程中预定义
. = . + _Min_Heap_Size; //动态扩展堆空间
. = . + _Min_Stack_Size; //动态扩展栈空间
. = ALIGN(8);
} >PSRAM

/DISCARD/ : //指令显式丢弃编译器标准库中的特定内容
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
} //强制链接器忽略libc.a(C标准库)、libm.a(数学库)、libgcc.a(GCC运行时库)的所有内容

//收集所有输入文件的.ARM.attributes段到输出文件
.ARM.attributes 0 : { *(.ARM.attributes) }
}

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容