0X00 链接文件介绍
这里以KEA128芯片,使用KDS编译为例,链接文件顾名思义就是嵌入式工程在链接阶段所要用到的文件,source文件在编译过程完成之后(此时已经是机器可识别的二进制机器码数据),需要再经过链接器从而将二进制数据有序组织起来形成最终的二进制可执行文件,该二进制文件最终会被下载进芯片内部非易失性存储器里。linker文件就是用来指示链接器如何组织编译生成的二进制数据。
0X01 链接文件源文件
/* Linker file for GNU C Compiler */
/* Entry Point */
ENTRY(Reset_Handler)
/* DEFINED(symbol)用于判断symbol在符号表中是否有定义,如果有定义则返回1否则返回0 */
HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x00000400;
STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x00000400;
M_VECTOR_RAM_SIZE = DEFINED(__flash_vector_table__) ? 0x0 : 0x00C0;
/*MEMORY
{
m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000100
m_flash_config (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010
m_text (RX) : ORIGIN = 0x00000410, LENGTH = 0x0001FBF0
m_data (RW) : ORIGIN = 0x1FFFF000, LENGTH = 0x00004000
}*/
__start_sector__ = 32; /*用户程序起始扇区号*/
/* Specify the memory areas *//* 定义内存区域的起始地址和长度 */
MEMORY
{
/*0扇区,中断向量区*/
m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000100
/*flash配置区,用于设置flash的配置信息*/
m_flash_config (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010
/*~占用前面32个扇区*/
m_text (RX) : ORIGIN = 0x00000410, LENGTH =__start_sector__*0x400- 0x0410
/*33扇区,放置flash版本固化信息*/
m_mac_config (RX) : ORIGIN = __start_sector__ *0x400, LENGTH = 0x00000400
/*RAM区,16KB*/
m_data (RW) : ORIGIN = 0x1FFFF000, LENGTH = 0x00004000
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into internal flash */
.interrupts :
{
__VECTOR_TABLE = .;
. = ALIGN(4);
/*
isr_vector在start.S中定义:.section .isr_vector, "a",按照MEMORY命令说明,
isr_vector由于没有指定输出section,因此会创建与输入section同名的输出section,且会按照
isr_vector的属性放到合适的内存区域,此处KEEP是保证isr_vector的输出section不会被删除
*/
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} > m_interrupts
.flash_config :
{
. = 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* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
} > m_text
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > m_text
.ARM :
{
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} > m_text
.ctors :
{
__CTOR_LIST__ = .;
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
from the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
__CTOR_END__ = .;
} > m_text
.dtors :
{
__DTOR_LIST__ = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
__DTOR_END__ = .;
} > m_text
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} > m_text
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} > m_text
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} > m_text
__etext = .; /* define a global symbol at end of code */
__DATA_ROM = .; /* Symbol is used by startup for data initialization */
.mac_config :
{
. = ALIGN(4);
KEEP(*(.MacConfig)) /* Flash Configuration Field (FCF) */
. = ALIGN(4);
} > m_mac_config
/* reserve MTB memory at the beginning of 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__) ;
/*vectors*/
.uservectors :
{
. = ALIGN(4);
__VECTOR_RAM__ = .;
__interrupts_ram_start__ = .; /* 定义起点处为__interrupts_ram_start__ */
. += M_VECTOR_RAM_SIZE;
. = ALIGN(4);
__interrupts_ram_end__ = .; /* 定义结尾处为__interrupts_ram_end__ */
} > m_data
/* reserve MTB memory at the beginning of m_data */
.mtb : /* MTB buffer address as defined by the hardware */
{
. = ALIGN(8);
_mtb_start = .;
KEEP(*(.mtb_buf)) /* need to KEEP Micro Trace Buffer as not referenced by application */
. = ALIGN(8);
_mtb_end = .;
} > m_data
.data : AT(__DATA_ROM)
{
. = ALIGN(4);
__DATA_RAM = .;
__data_start__ = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
KEEP(*(.jcr*))
. = ALIGN(4);
__data_end__ = .; /* define a global symbol at data end */
} > m_data
/* Uninitialized data section 使用直接地址的RAM空间*/
.impinfo :
{
. = ALIGN(4);
KEEP(*(.impinfo*))
. = ALIGN(4);
} > m_data
/* Uninitialized data section */
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
. = ALIGN(4);
__START_BSS = .;
__bss_start__ = .;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
__END_BSS = .;
} > m_data
/* Symbol is used by startup for data initialization */
__DATA_END = __DATA_ROM + (__data_end__ - __data_start__);
.heap :
{
. = ALIGN(8);
__end__ = .;
PROVIDE(end = .);
__HeapBase = .;
. += HEAP_SIZE;
__HeapLimit = .;
} > m_data
.stack :
{
. = ALIGN(8);
. += STACK_SIZE;
} > m_data
/* Initializes stack on the end of block */
__StackTop = ORIGIN(m_data) + LENGTH(m_data);
__StackLimit = __StackTop - STACK_SIZE;
PROVIDE(__stack = __StackTop);
.ARM.attributes 0 : { *(.ARM.attributes) }
ASSERT(__StackLimit >= __HeapLimit, "region m_data overflowed with stack and heap")
}
0X01 链接文件详细解析
/* Entry Point */
ENTRY(Reset_Handler)
程序入口点,进入到启动文件的Reset_Handler函数中,有关于Reset_Handler 函数的解析请看另一篇关于中断向量表的文章。
HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x00000400;
STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x00000400;
M_VECTOR_RAM_SIZE = DEFINED(__flash_vector_table__) ? 0x0 : 0x00C0;
DEFINED(symbol)用于判断symbol在符号表中是否有定义,如果有定义则返回1否则返回0
设堆栈与中断向量表大小,HEAP_SIZE与STACK_SIZE的大小为1KB,M_VECTOR_RAM_SIZE大小为192B。
__start_sector__ = 32; /*用户程序起始扇区号*/
/* 定义内存区域的起始地址和长度 */
MEMORY
{
/*0扇区,中断向量区*/
m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000100
/*flash配置区,用于设置flash的配置信息*/
m_flash_config (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010
/*~占用前面32个扇区*/
m_text (RX) : ORIGIN = 0x00000410, LENGTH =__start_sector__*0x400- 0x0410
/*33扇区,放置flash版本固化信息*/
m_mac_config (RX) : ORIGIN = __start_sector__ *0x400, LENGTH = 0x00000400
/*RAM区,16KB*/
m_data (RW) : ORIGIN = 0x1FFFF000, LENGTH = 0x00004000
}
定义内存区域,用户起始扇区为32扇区号。中断向量区扇区号0-256。flash配置区扇区号1024-1040。 m_text(代码区) 起始扇区号1040,长度通过用户扇区计算。m_mac_config(flash版本信息)32个扇区。m_data(数据区)占用16384个扇区。
/* The startup code goes first into internal flash */
.interrupts :
{
__VECTOR_TABLE = .;
. = ALIGN(4);
/*
isr_vector在start.S中定义:.section .isr_vector, "a",按照MEMORY命令说明,
isr_vector由于没有指定输出section,因此会创建与输入section同名的输出section,且会按照
isr_vector的属性放到合适的内存区域,此处KEEP是保证isr_vector的输出section不会被删除
*/
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} > m_interrupts
中断向量表的地址全部都链接到0x00000000,采用4字节方式。