HPM6750 在RT-Thread Studio 中链接文件 flash_rtt.ld 注释说明
链接文件包含3个文件,文件位置:board -> linker_scripts
文件1 flash_rtt_enet.ld
文件2 flash_rtt.ld
文件3 ram_rtt.ld
这里使用的是文件2,其说明如下:
/*
* Copyright 2021 - 2022 hpmicro
* SPDX-License-Identifier: BSD-3-Clause
* 链接脚本官方文档:https://sourceware.org/binutils/docs-2.39/ld.html
* 链接脚本文件(.ld .lds)详解:https://www.cnblogs.com/god-of-death/p/14879078.html
* Linux下的lds链接脚本详解:https://www.cnblogs.com/li-hao/p/4107964.html
*/
/*
指定输出可执行文件的起始代码段为_start.
*/
ENTRY(_start)
/*
指定分配内存大小
*/
STACK_SIZE = DEFINED(_stack_size) ? _stack_size : 16k;
HEAP_SIZE = DEFINED(_heap_size) ? _heap_size : 16k;
FLASH_SIZE = DEFINED(_flash_size) ? _flash_size : 16M;
SDRAM_SIZE = DEFINED(_sdram_size) ? _sdram_size : 8M;
NONCACHEABLE_SIZE = DEFINED(_noncacheable_size) ? _noncacheable_size : 1M;
FLASH_BOOT_SIZE = DEFINED(_boot_size) ? _boot_size : 1M; /* 1M */
FLASH_APP_SIZE = DEFINED(_flash_app_size) ? _flash_app_size : (FLASH_SIZE - FLASH_BOOT_SIZE);
/*
脚本中以 MEMORY 命令定义了存储空间,其中以 ORIGIN 定义地址空间的起始地址, LENGTH 定义地址空间的长度
MEMORY
{
NAME1 [(ATTR)] : ORIGIN = ORIGIN1, LENGTH = LEN2
NAME2 [(ATTR)] : ORIGIN = ORIGIN2, LENGTH = LEN2
}
NAME :存储区域的名字.(自己可以随意命名)
ATTR :定义该存储区域的属性.ATTR属性内可以出现以下7个字符:
R 只读section
W 读/写section
X 可执行section
A 可分配的section
I 初始化了的section
L 同 I
! 不满足该字符之后的任何一个属性的section
ORIGIN :关键字,区域的开始地址,可简写成 org 或 o
LENGTH :关键字,区域的大小,可简写成 len 或 l
*/
MEMORY
{
/* XPI0(即连接的片外串行NOR Flash)的起始位置 bootloader address*/
XPI0 (rx) : ORIGIN = 0x80000000, LENGTH = FLASH_SIZE /* XPI0 */
/* XPI0(即连接的片外串行NOR Flash)的起始位置 app address */
XPI0_APP (rx) : ORIGIN = 0x80100000, LENGTH = FLASH_APP_SIZE
/* 指令本地存储器(ILM)的访问频率与 CPU 相同,支持零等待周期访问.*/
ILM (wx) : ORIGIN = 0x00000000, LENGTH = 256K /* ILM */
/* 数据本地存储器(DLM)的访问频率与 CPU 相同,支持零等待周期访问 */
DLM (w) : ORIGIN = 0x00080000, LENGTH = 256K /* DLM */
/* CPU0 指令/数据本地存储器 */
CPU0_ILM_SLV (wx) : ORIGIN = 0x01000000, LENGTH = 256K /* CPU0_ILM_SLV */
CPU0_DLM_SLV (w) : ORIGIN = 0x01040000, LENGTH = 256K /* CPU0_DLM_SLV */
/* 正常 AXI SRAM 地址分配*/
AXI_SRAM0 (wx) : ORIGIN = 0x01080000, LENGTH = 512K /* AXI SRAM0 */
AXI_SRAM1 (wx) : ORIGIN = 0x01100000, LENGTH = 512K /* AXI SRAM1 */
/* AXI SRAM1 地址单独分配*/
NONCACHEABLE_AXI_SRAM1 (w) : ORIGIN = 0x01100000, LENGTH = 256K /* AXI SRAM1 */
/* CPU1 指令/数据本地存储器 */
CPU1_ILM_SLV (wx) : ORIGIN = 0x01180000, LENGTH = 256K /* CPU1_ILM_SLV */
CPU1_DLM_SLV (w) : ORIGIN = 0x011C0000, LENGTH = 256K /* CPU1_DLM_SLV */
/* SRAM */
SHARE_RAM (w) : ORIGIN = 0x0117C000, LENGTH = 16K /* SHARE_RAM */
AHB_SRAM (w) : ORIGIN = 0xF0300000, LENGTH = 32k /* AHB_SRAM */
APB_SRAM (w) : ORIGIN = 0xF40F0000, LENGTH = 8k /* APB_SRAM */
SDRAM (wx) : ORIGIN = 0x40000000, LENGTH = SDRAM_SIZE - NONCACHEABLE_SIZE
SDRAM_NONCACHEABLE (wx) : ORIGIN = 0x40000000 + SDRAM_SIZE - NONCACHEABLE_SIZE, LENGTH = NONCACHEABLE_SIZE
}
/*
__nor_cfg_option_load_addr__ 区域,用来存放外部串行 NOR flash 的配置信息,在
MCU 启动时 BOOT ROM 会根据此配置信息,来初始化 XPI0 端口,用于后续
进一步与 NOR Flash 通讯.在当前 linker 文件,将 __nor_cfg_option_load_addr__ 区域
指定在地址 0x80000400,即串行总线控制器 XPI0 存储空间映射的 0x400 偏
移位置,对应与 XPI0 连接的串行 NOR Flash 地址偏移 0x400.
*/
__nor_cfg_option_load_addr__ = ORIGIN(XPI0) + 0x400; /* size 0x0C00 */
/*
__boot_header_load_addr__ 区域,用来存放用户代码镜像的固件容器头,在 MCU 启
动时 BOOT ROM 会根据固件容器头,进一步执行启动流程.在当前 linker 文
件,将 __boot_header_load_addr__ 区域指定在地址 0x80001000,即串行总线控制器
XPI0 存储空间映射的 0x1000 偏移位置,对应与 XPI0 连接的串行 NOR Flash
地址偏移 0x1000.
*/
__boot_header_load_addr__ = ORIGIN(XPI0) + 0x1000; /* size 0x2000 */
/*
__app_load_addr__ 区域,即用户代码镜像的存储位置.在当前 linker 文件,将 __app_load_addr__ 区
域指定在地址 0x80003000,即串行总线控制器 XPI0 存储空间映射的 0x3000
偏移位置,对应与 XPI0 连接的串行 NOR Flash 地址偏移 0x3000.显然,此偏
移之前的区域,保留给了 NOR_CFG_OPTION 区域和 BOOT_HEADER 区域.
*/
__app_load_addr__ = ORIGIN(XPI0) + 0x3000; /* code start address 12k */
__boot_header_length__ = __boot_header_end__ - __boot_header_start__;
__app_offset__ = __app_load_addr__ - __boot_header_load_addr__;
/*
The SECTIONS command tells the linker how to map input sections into output sections,
and how to place the output sections in memory.
*/
SECTIONS
{
.nor_cfg_option __nor_cfg_option_load_addr__ :
{
/*
*表示所有的输入文件
所以 *(.nor_cfg_option) 表示从所有的输入文件中获取所有 .nor_cfg_option section放在一块连续的地址空间
*/
KEEP(*(.nor_cfg_option)) /* KEEP 强制让链接器保留一些特定的section,防止被优化 */
} > XPI0 /* 定义的位置信息,指定section在哪个memory执行*/
.boot_header __boot_header_load_addr__ :
{
__boot_header_start__ = .;
KEEP(*(.boot_header))
KEEP(*(.fw_info_table))
KEEP(*(.dc_info))
__boot_header_end__ = .;
} > XPI0
.start __app_load_addr__ :
{
. = ALIGN(8); /* 以8字节对齐 */
KEEP(*(.start))
} > XPI0
/*
代码段 放在一块连续的地址空间
*/
.text (__vector_load_addr__ + __vector_ram_end__ - __vector_ram_start__) :
{
. = ALIGN(8);
*(.text) /* 其它代码部分 */
*(.text*)
*(.rodata) /* 指定只读数据段 */
*(.rodata*)
*(.srodata)
*(.srodata*)
*(.hash)
*(.dyn*)
*(.gnu*)
*(.pl*)
KEEP(*(.eh_frame))
*(.eh_frame*)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(8);
/*********************************************
*
* RT-Thread related sections - Start
*
*********************************************/
/* section information for finsh shell */
. = ALIGN(4);
__fsymtab_start = .;
KEEP(*(FSymTab))
__fsymtab_end = .;
. = ALIGN(4);
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
. = ALIGN(4);
. = ALIGN(4);
__rt_init_start = .;
KEEP(*(SORT(.rti_fn*)))
__rt_init_end = .;
. = ALIGN(4);
/* section information for modules */
. = ALIGN(4);
__rtmsymtab_start = .;
KEEP(*(RTMSymTab))
__rtmsymtab_end = .;
/* RT-Thread related sections - end */
} > XPI0
.rel :
{
KEEP(*(.rel*))
} > XPI0
/* section information for usbh class */
.usbh_class_info : {
. = ALIGN(4);
__usbh_class_info_start__ = .;
KEEP(*(.usbh_class_info))
__usbh_class_info_end__ = .;
. = ALIGN(8);
} > XPI0
/*
PROVIDE 关键字定义一个 (输入文件内被引用但没定义) 符号,
相当于定义一个全局变量的符号表,
其他C文件可以通过该符号来操作对应的存储内存
*/
/*
在链接脚本中声明了_etext 符号,特别注意的是_etext 只是一个符号,没有存储内存,
并不是一个变量,该符号对应(映射)的是一个地址,其地址为 .rel section 之后的第1个地址
*/
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
__vector_load_addr__ = ADDR(.start) + SIZEOF(.start);
/*
vectors: RISC-V CPU 的中断向量表, hpm sdk 默认打开了 RISC-V CPU
的中断向量扩展和中断嵌套扩展,每一个外部中断都在中断向量表中占有一个
32 位长的入口. block vectors 包含的就是中断向量表.
为了便于快速访问,以复制的形式指定到片内 ILM 的镜像地址
*/
.vectors : AT(__vector_load_addr__) /* AT指令 定义本段存储(加载)的地址 */
{
. = ALIGN(8);
__vector_ram_start__ = .;
KEEP(*(.vector_table))
KEEP(*(.isr_vector))
. = ALIGN(8);
__vector_ram_end__ = .;
} > ILM /* AXI_SRAM0 -> ILM */
/*
程序数据段存储,以复制的形式进行初始化
注意:当芯片没有外挂SDRAM时,需要定义到内部SRAM
*/
.data : AT(etext) /* AT指令 定义本段存储(加载)的地址 */
{
. = ALIGN(8);
__data_start__ = .;
__global_pointer$ = . + 0x800;
*(.data) /* 表示将所有的输入文件的 .data section 链接到输出文件 .data section 中 */
*(.data*) /* 程序的数据段,会以复制的形式进行初始化 */
*(.sdata)
*(.sdata*)
*(.tdata)
*(.tdata*)
KEEP(*(.jcr))
KEEP(*(.dynamic))
KEEP(*(.got*))
KEEP(*(.got))
KEEP(*(.gcc_except_table))
KEEP(*(.gcc_except_table.*))
. = ALIGN(8);
PROVIDE(__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE(__preinit_array_end = .);
. = ALIGN(8);
PROVIDE(__init_array_start = .);
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*)))
KEEP(*(.init_array))
PROVIDE(__init_array_end = .);
. = ALIGN(8);
PROVIDE(__finit_array_start = .);
KEEP(*(SORT_BY_INIT_PRIORITY(.finit_array.*)))
KEEP(*(.finit_array))
PROVIDE(__finit_array_end = .);
. = ALIGN(8);
KEEP(*crtbegin*.o(.ctors))
KEEP(*(EXCLUDE_FILE (*crtend*.o) .ctors))
KEEP(*(SORT(.ctors.*)))
KEEP(*(.ctors))
. = ALIGN(8);
KEEP(*crtbegin*.o(.dtors))
KEEP(*(EXCLUDE_FILE (*crtend*.o) .dtors))
KEEP(*(SORT(.dtors.*)))
KEEP(*(.dtors))
. = ALIGN(8);
__data_end__ = .;
PROVIDE (__edata = .);
PROVIDE (_edata = .);
PROVIDE (edata = .);
} > AXI_SRAM0 /* SDRAM -> AXI_SRAM0 */
/*
.fast 为复制到内部 RAM 执行的代码,也在初始化阶段复制到 RAM 中
一些对执行性能有要求的代码,可以分配到此 section
*/
.fast : AT(etext + __data_end__ - __data_start__) /* AT指令 定义本段存储(加载)的地址 */
{
. = ALIGN(8);
__ramfunc_start__ = .;
*(.fast)
/* RT-Thread Core Start */
KEEP(*context_gcc.o(.text* .rodata*))
KEEP(*cpuport.o (.text .text* .rodata .rodata*))
KEEP(*trap_entry.o (.text .text* .rodata .rodata*))
KEEP(*irq.o (.text .text* .rodata .rodata*))
KEEP(*clock.o (.text .text* .rodata .rodata*))
KEEP(*kservice.o (.text .text* .rodata .rodata*))
KEEP(*scheduler.o (.text .text* .rodata .rodata*))
KEEP(*trap.o (.text .text* .rodata .rodata*))
KEEP(*idle.o (.text .text* .rodata .rodata*))
KEEP(*ipc.o (.text .text* .rodata .rodata*))
KEEP(*thread.o (.text .text* .rodata .rodata*))
KEEP(*object.o (.text .text* .rodata .rodata*))
KEEP(*timer.o (.text .text* .rodata .rodata*))
KEEP(*mem.o (.text .text* .rodata .rodata*))
KEEP(*mempool.o (.text .text* .rodata .rodata*))
/* RT-Thread Core End */
. = ALIGN(8);
__ramfunc_end__ = .;
} > ILM /* AXI_SRAM0 -> ILM */
__fw_size__ = __ramfunc_end__ - __ramfunc_start__ + __data_end__ - __data_start__ + etext - __app_load_addr__;
/*
指定bss段
注意:当芯片没有外挂SDRAM时,需要定义到内部SRAM
*/
.bss (NOLOAD) :
{
. = ALIGN(8);
__bss_start__ = .;
*(.bss)
*(.bss*)
*(.tbss*)
*(.sbss*)
*(.scommon)
*(.scommon*)
*(.tcommon*)
*(.dynsbss*)
*(COMMON)
. = ALIGN(8);
_end = .; /* 把_end赋值为当前位置,即bss段的结束位置 */
__bss_end__ = .;
} > AXI_SRAM0 /* SDRAM -> AXI_SRAM0 */
/*
framebuffer,通常用作通讯接口的收发数据缓冲,分配到通用内存 AXI SRAM 中
注意:当芯片没有外挂SDRAM时,需要定义到内部SRAM
*/
.framebuffer (NOLOAD) :
{
. = ALIGN(8);
KEEP(*(.framebuffer))
. = ALIGN(8);
} > SDRAM /* AXI_SRAM0 -> SDRAM */
/*
noncacheable 不需要初始化的 section
*/
.noncacheable (NOLOAD) : AT(etext + __data_end__ - __data_start__ + __ramfunc_end__ - __ramfunc_start__) /* AT指令 定义本段存储(加载)的地址 */
{
. = ALIGN(8);
__noncacheable_init_start__ = .;
KEEP(*(.noncacheable.init))
__noncacheable_init_end__ = .;
KEEP(*(.noncacheable))
__noncacheable_bss_start__ = .;
KEEP(*(.noncacheable.bss))
__noncacheable_bss_end__ = .;
. = ALIGN(8);
} > NONCACHEABLE_AXI_SRAM1 /* SDRAM_NONCACHEABLE -> AXI_SRAM0 -> NONCACHEABLE_AXI_SRAM1*/
.sh_mem (NOLOAD) :
{
KEEP(*(.sh_mem))
} > SHARE_RAM
.ahb_sram (NOLOAD) :
{
KEEP(*(.ahb_sram))
} > AHB_SRAM
.apb_sram (NOLOAD) :
{
KEEP(*(.backup_sram))
} > APB_SRAM
.fast_ram (NOLOAD) : {
KEEP(*(.fast_ram))
} > DLM
/* heap: block heap 包含了程序的堆, 堆是用于存放进程运行中被动态分
配的内存段,它的大小并不固定,可动态扩张或缩减.当进程调用 malloc 等函
数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张); 当利用free等
函数释放内存时,被释放的内存从堆中被剔除(堆被缩减);
注意:当芯片没有外挂SDRAM时,需要定义到内部SRAM
*/
.heap (NOLOAD) :
{
. = ALIGN(8);
__heap_start__ = .;
. += HEAP_SIZE;
__heap_end__ = .;
} > SDRAM /* SDRAM -> AXI_SRAM0 -> DLM */
/*
stack: block stack 包含了程序的栈, 是用户存放程序临时创建的局部变
量. 除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并
且待到调用结束后,函数的返回值也会被存放回栈中.由于栈的先进先出(FIFO)
特点,所以栈也用来保存/恢复调用现场. 比如 RISC-V CPU 响应中断时,也会
将当前 CPU 内现场数据保存到 stack
注意:当芯片没有外挂SDRAM时,需要定义到内部SRAM
*/
.stack (NOLOAD) :
{
. = ALIGN(8);
__stack_base__ = .;
. += STACK_SIZE;
. = ALIGN(8);
PROVIDE (_stack = .);
PROVIDE (_stack_in_dlm = .);
} > DLM /* AXI_SRAM0 -> DLM */
__noncacheable_start__ = ORIGIN(SDRAM_NONCACHEABLE);
__noncacheable_end__ = ORIGIN(SDRAM_NONCACHEABLE) + LENGTH(SDRAM_NONCACHEABLE);
__share_mem_start__ = ORIGIN(SHARE_RAM);
__share_mem_end__ = ORIGIN(SHARE_RAM) + LENGTH(SHARE_RAM);
ASSERT((STACK_SIZE + HEAP_SIZE) <= 256K, "stack and heap total size larger than 256k")
}
由于使用的是 gcc 编译工具链,这里格式按照 gcc的格式来编写和修改;
如果使用的是SES的开发工具链,这套链接文件应该无法正常使用。
本文来自博客园,作者:求隐,转载请注明原文链接:https://www.cnblogs.com/duguqiuying/articles/17807237.html

浙公网安备 33010602011771号