在S32DS for ARM 2018.R1自带的例程中有两个链接文件,分别为S32K1xx_flash.ld和S32K1xx_ram.ld,前者针对的是程序在flash中运行的链接文件,后者是在ram中运行程序所需要的链接文件。以下以S32K144的flash.ld文件为例,进行简单的分析
/* Entry Point */
ENTRY(Reset_Handler)/* 关键词ENTRY()指定应用程序入口函数,即复位中断服务函数,是MCU复位后执行的第一个函数 */
HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x00000400;/* 指定应用程序堆(heap)的大小,用于动态分配内存的RAM区域,heap的空间是用户手动申请和释放的 :C语言中的malloc(size), calloc(num, size)函数分配heap,释放使用free(*heap)函数。如果用户没有定义__heap_size__,则应用程序堆大小为默认的1024字节 */
STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x00000400;/* 指定应用程序栈(stack)的大小,栈被用于函数调用/中断服务函数调用时的CPU内核寄存器和上下文(Context)的保存、函数形参的传递和局部变量存储,其遵循先压栈后出栈(FILO—First In Last Out),原则,运行时有CPU内核自动控制。如果用户没有定义__stack_size__则应用程序栈大小为默认的1024字节 */
/* If symbol __flash_vector_table__=1 is defined at link time
* the interrupt vector will not be copied to RAM.
* Warning: Using the interrupt vector from Flash will not allow
* INT_SYS_InstallHandler because the section is Read Only.
*/
M_VECTOR_RAM_SIZE = DEFINED(__flash_vector_table__) ? 0x0 : 0x0400;/* 如果定义了__flash_vector_table__,M_VECTOR_RAM_SIZE就等于0,从而导致__VECTOR_RAM等于__VECTOR_TABLE,在startup.c文件根据此条件中断向量表就不会拷贝到RAM中,此时就没法在程序中调用INT_SYS_InstallHandler进行中断处理函数的安装 */
/* Specify the memory areas */
MEMORY
{
/* Flash */
m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000400/* 中断向量表/启动代码,起始地址为0x000,长度0x400 */
m_flash_config (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010/* flash配置信息存放位置,起始地址为0x400,长度为0x10 */
m_text (RX) : ORIGIN = 0x00000410, LENGTH = 0x0007FBF0/* 主要代码/数据存储区,起始地址为0x410,长度为512K-0x410;除此而外,S32K144还有64KFleNVM,可用作P-Flash或D-Flash,即FlexNVM可用于程序或数据存储。如果用作P-Flash,由于FlexNVM不可缓存;因此,可能会出现性能下降。 */
/* SRAM_L */
m_data (RW) : ORIGIN = 0x1FFF8000, LENGTH = 0x00008000/* SRAM_L包含.interrupts_ram段.data段和.code段,起始地址为0x1FFF8000,长度为32K;S32K的SRAM具有ECC功能,用户在启动函数start()中,最开始对SRAM进行写值(将内核通用寄存器值写入SRAM)操作,初始化ECC。所有带硬件ECC功能的系统存储器读取前都必须先对其进行写值/擦除(对Flash和EEPROM)操作,产生初始的ECC,否则读取时将产生ECC错误 */
/* SRAM_U */
m_data_2 (RW) : ORIGIN = 0x20000000, LENGTH = 0x00007000/* SRAM_U包含.customSectionBlock段.bss段.heap段和.stack段,起始地址为0x20000000,长度为28K;S32K144总共64KRAM,还有4KRAM是flexRAM,可用于传统的SRAM,但它不像主SRAM那样具有ECC,并且以flash的时钟速度运行 */
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into internal flash */
.interrupts :/* 启动段 */
{
__VECTOR_TABLE = .;/* 标记向量表开始地址,"."表示当前地址 */
__interrupts_start__ = .;/* 标记驱动段开始地址 */
. = ALIGN(4);/* 使用关键词ALIGN() 将其4字节对齐 */
KEEP(*(.isr_vector)) /* Startup code 使用关键词KEEP,将.isr_vector段始终保持在此段内 */
__interrupts_end__ = .;/* 标记驱动段结束地址 */
. = ALIGN(4);
} > m_interrupts/* 链接到m_interrupts分区 */
.flash_config :/* flash配置信息存放区域 */
{
. = ALIGN(4);
KEEP(*(.FlashConfig)) /* Flash Configuration Field (FCF) */
. = ALIGN(4);
} > m_flash_config
/* The program code and other data goes into internal flash */
.text :/* 主要代码和数据存储区 */
{
. = ALIGN(4);
*(.text) /* .text sections (code) 所有文件中的.text段 */
*(.text*) /* .text* sections (code) 所有文件中以.text开始的段 */
*(.rodata) /* .rodata sections (constants, strings, etc.)只读数据段,由于存储const修饰的常量 */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.init) /* section used in crti.o files 在crti.o文件中使用此段 */
*(.fini) /* section used in crti.o files */
*(.eh_frame) /* section used in crtbegin.o files */
. = ALIGN(4);
} > m_text
/* Section used by the libgcc.a library for fvp4 用于存放ARM的FVP4信息 */
.ARM :
{
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} > m_text
__etext = .; /* Define a global symbol at end of code. */
__DATA_ROM = .; /* Symbol is used by startup for data initialization.启动过程中初始化.data段需要引用此符号 */
.interrupts_ram :/* ram中的中断向量段 */
{
. = ALIGN(4);
__VECTOR_RAM__ = .;
__RAM_START = .;
__interrupts_ram_start__ = .; /* Create a global symbol at data start. */
*(.m_interrupts_ram) /* This is a user defined section. */
. += M_VECTOR_RAM_SIZE;
. = ALIGN(4);
__interrupts_ram_end__ = .; /* Define a global symbol at data end. */
} > m_data
__VECTOR_RAM = DEFINED(__flash_vector_table__) ? ORIGIN(m_interrupts) : __VECTOR_RAM__ ;
__RAM_VECTOR_TABLE_SIZE = DEFINED(__flash_vector_table__) ? 0x0 : (__interrupts_ram_end__ - __interrupts_ram_start__) ;
.data : AT(__DATA_ROM)/* .data段(存放初始化值不为0的全局变量) 关键词AT(),将其存储并从__DTA_ROM分区加载 */
{
. = ALIGN(4);
__DATA_RAM = .;
__data_start__ = .; /* Create a global symbol at data start. */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
__data_end__ = .; /* Define a global symbol at data end. */
} > m_data
__DATA_END = __DATA_ROM + (__data_end__ - __data_start__);
__CODE_ROM = __DATA_END; /* Symbol is used by code initialization. */
.code : AT(__CODE_ROM)/* .code段,通过__attribute__((section (".code_ram")))将需要重映射的代码/函数指定到RAM中的.code_ram段运行 */
{
. = ALIGN(4);
__CODE_RAM = .;
__code_start__ = .; /* Create a global symbol at code start. */
__code_ram_start__ = .;
*(.code_ram) /* Custom section for storing code in RAM */
. = ALIGN(4);
__code_end__ = .; /* Define a global symbol at code end. */
__code_ram_end__ = .;
} > m_data
__CODE_END = __CODE_ROM + (__code_end__ - __code_start__);
__CUSTOM_ROM = __CODE_END;
/* Custom Section Block that can be used to place data at absolute address. */
/* Use __attribute__((section (".customSection"))) to place data here. 使用__attribute__((section (".customSection")))将需要固定地址的函数从0x20000000开始安放,具体可以查看map文件中需要固定地址的函数,注意不要用static修饰,不然在map文件中只能看到文件名,看不到具体的函数名以及地址 */
.customSectionBlock ORIGIN(m_data_2) : AT(__CUSTOM_ROM)
{
__customSection_start__ = .;
KEEP(*(.customSection)) /* Keep section even if not referenced. */
__customSection_end__ = .;
} > m_data_2
__CUSTOM_END = __CUSTOM_ROM + (__customSection_end__ - __customSection_start__);
/* Uninitialized data section. */
.bss :/* .bss段,存放未初始化或初始化值为0的全局变量 */
{
/* This is used by the startup in order to initialize the .bss section. */
. = ALIGN(4);
__BSS_START = .;
__bss_start__ = .;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
__BSS_END = .;
} > m_data_2
/* Put heap section after the program data */
.heap :/* 堆区 */
{
. = ALIGN(8);
__end__ = .;
__heap_start__ = .;
PROVIDE(end = .);
PROVIDE(_end = .);
PROVIDE(__end = .);
__HeapBase = .;
. += HEAP_SIZE;
__HeapLimit = .;
__heap_limit = .;
__heap_end__ = .;
} > m_data_2
/* Initializes stack on the end of block */
__StackTop = ORIGIN(m_data_2) + LENGTH(m_data_2);
__StackLimit = __StackTop - STACK_SIZE;
PROVIDE(__stack = __StackTop);
__RAM_END = __StackTop;
.stack __StackLimit :/* 栈区 */
{
. = ALIGN(8);
__stack_start__ = .;
. += STACK_SIZE;
__stack_end__ = .;
} > m_data_2
.ARM.attributes 0 : { *(.ARM.attributes) }
ASSERT(__StackLimit >= __HeapLimit, "region m_data_2 overflowed with stack and heap")/* 断言函数,判断m_data_2是否越界 */
}