ld文件与startup启动文件的作用是二者配合,在运行main之前需要一系列的初始化工作。这里面很重要的一个就是内存空间的分配,也就是用来存放常数、已初始化参数和未参数化参数的地址。这就涉及到其中很重要的堆栈概念。这是在51单片机书籍中经常出现的一个概念,使用SP表示,也就是堆栈指针,存放一个特定的地址,通过指向地址的地址指针概念实现数据访问。其实呢,堆栈可以分为堆和栈两个概念。栈在英语中对应的是stack,堆对应的英语单词是heap,二者的作用是不同的。使用网络上的一段话就是,
内存中的栈区处于相对较高的地址以地址的增长方向为上的话,栈地址是向下增长的,栈中分配局部变量空间,堆区是向上增长的用于分配程序员申请的内存空间。另外还有静态区是分配静态变量,全局变量空间的;只读区是分配常量和程序代码空间的;及其他一些分区。
来看一个网上很流行的经典例子:
main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456/0在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10); 堆
p2 = (char *)malloc(20); 堆
}
如何为程序中的变量等申请并分配空间呢,这就是ld文件的作用,通过linker生成最终的hex文件。经过测试,一个可以在emIDE和EmBITZ下使用的ld文件如下。申请了256,也就是0x100个字节的堆和栈,对应变量为
_Min_Heap_Size = 0x100; /*堆大小*/
_Min_Stack_Size = 0x100; /*栈大小*/
如果需要其他不同字节的堆和栈,直接修改这两个参数就可。如果申请的空间过大,系统会编译出错。
MEMORY
{
FLASH (rx) : ORIGIN = 0x0000000, LENGTH = 64K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 4K
}
_Min_Heap_Size = 0x100; /* required amount of heap */
_Min_Stack_Size = 0x100; /* required amount of stack */
/************************************************************************************
*
* Code and data sections
************************************************************************************/
ENTRY(Reset_Handler)
SECTIONS
{
/************************************************************************************
*
* text section (code)
* Starts with startup code and vectors
* Goes into FLASH
************************************************************************************/
.text :
{
/* Interrupt vector table */
KEEP(*(.isr_vector))
. = ALIGN(0x100);
/* Code section */
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
/* Rodata section (constants, strincs, ...) */
*(.rodata*)
KEEP(*(.eh_frame*))
} > FLASH
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
.ARM.attributes : {
*(.ARM.attributes)
} > FLASH
/* Global symbol at the end of code (text section) */
. = ALIGN(4);
__etext = .;
/************************************************************************************
*
* data section
* Goes into RAM
************************************************************************************/
.data : AT (__etext)
{
/* Global symbol at start of data */
__data_start__ = .;
*(vtable)
*(.data*)
. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
KEEP(*(.jcr*))
. = ALIGN(4);
/* Global symbol at end of data */
__data_end__ = .;
} > RAM
/************************************************************************************
*
* bss section (Uninitialized data)
* Goes into RAM
************************************************************************************/
.bss :
{
. = ALIGN(4);
/* Global symbol at start of bss */
__bss_start__ = .;
*(.bss*)
*(COMMON)
. = ALIGN(4);
/* Global symbol at end of bss */
__bss_end__ = .;
} > RAM
/************************************************************************************
*
* user_heap_stack section
* Check that there is enough RAM left for stack and heap
************************************************************************************/
._user_heap_stack :
{
. = ALIGN(8);
__heap_start__ = .;
. = . + _Min_Heap_Size;
__heap_end__ = .;
. = ALIGN(8);
__stack_start__ = .;
. = . + _Min_Stack_Size;
__stack_end__ = .;
_estack = .;
. = ALIGN(8);
} >RAM
/************************************************************************************
*
* Remove information from the standard libraries
************************************************************************************/
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
}
根据你使用的芯片的Flash和SRAM大小,修改FLASH段的LENGTH。根据SRAM大小和映射地址,修改RAM段的ORIGIN起始地址和 LENGTH。如上文件在emIDE和EmBITZ下测试,可用于M051系列ARM的开发。
|