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的开发工具链,这套链接文件应该无法正常使用。

 

posted @ 2023-11-03 11:26  求隐  阅读(711)  评论(0)    收藏  举报