ld是GUN binutils工具集中的一个,是众多Linkers(链接器)的一种。其主要作用是完成链接器的基本功能:把各种目标文件和库文件链接起来,并重定向它们的数据,完成符号解析。
Linking主要就是完成四个方面的工作:分配存储器、管理标识符、库和代码迁移。
ld可以识别一种Linker command Language表示的linker scriopt文件来显示的控制链接的过程。通过BFD(Binary Format Description)库,ld可以读取和操作COFF(common object file format)、ELF(executable and linking format)、a.out等各种格式的目标文件。
下面就对led_test实例工程中的stm32f103zet6_flash.ld进行简单的说明。
/\* Entry Point \*/
ENTRY(Reset\_Handler)
/\* Highest address of the user mode stack \*/
\_estack = 0x20010000; /\* end of 64K RAM \*/
/\* Generate a link error if heap and stack don't fit into RAM \*/
\_Min\_Heap\_Size = 0; /\* required amount of heap \*/
\_Min\_Stack\_Size = 0x200; /\* required amount of stack \*/
/\* Specify the memory areas \*/
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
MEMORY\_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
}
/\* Define output sections \*/
SECTIONS
{
/\* The startup code goes first into FLASH \*/
.isr\_vector :
{
. = ALIGN(4);
KEEP(\*(.isr\_vector)) /\* Startup code \*/
. = ALIGN(4);
} >FLASH
/\* The program code and other data goes into 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 \*/
KEEP (\*(.init))
KEEP (\*(.fini))
. = ALIGN(4);
\_etext = .; /\* define a global symbols at end of code \*/
} >FLASH
.ARM.extab : { \*(.ARM.extab\* .gnu.linkonce.armextab.\*) } >FLASH
.ARM : {
\_\_exidx\_start = .;
\*(.ARM.exidx\*)
\_\_exidx\_end = .;
} >FLASH
.ARM.attributes : { \*(.ARM.attributes) } > FLASH
.preinit\_array :
{
PROVIDE\_HIDDEN (\_\_preinit\_array\_start = .);
KEEP (\*(.preinit\_array\*))
PROVIDE\_HIDDEN (\_\_preinit\_array\_end = .);
} >FLASH
.init\_array :
{
PROVIDE\_HIDDEN (\_\_init\_array\_start = .);
KEEP (\*(SORT(.init\_array.\*)))
KEEP (\*(.init\_array\*))
PROVIDE\_HIDDEN (\_\_init\_array\_end = .);
} >FLASH
.fini\_array :
{
PROVIDE\_HIDDEN (\_\_fini\_array\_start = .);
KEEP (\*(.fini\_array\*))
KEEP (\*(SORT(.fini\_array.\*)))
PROVIDE\_HIDDEN (\_\_fini\_array\_end = .);
} >FLASH
/\* used by the startup to initialize data \*/
\_sidata = .;
/\* Initialized data sections goes into RAM, load LMA copy after code \*/
.data : AT ( \_sidata )
{
. = ALIGN(4);
\_sdata = .; /\* create a global symbol at data start \*/
\*(.data) /\* .data sections \*/
\*(.data\*) /\* .data\* sections \*/
. = ALIGN(4);
\_edata = .; /\* define a global symbol at data end \*/
} >RAM
/\* Uninitialized data section \*/
. = ALIGN(4);
.bss :
{
/\* This is used by the startup in order to initialize the .bss secion \*/
\_sbss = .; /\* define a global symbol at bss start \*/
\_\_bss\_start\_\_ = \_sbss;
\*(.bss)
\*(.bss\*)
\*(COMMON)
. = ALIGN(4);
\_ebss = .; /\* define a global symbol at bss end \*/
\_\_bss\_end\_\_ = \_ebss;
} >RAM
PROVIDE ( end = \_ebss );
PROVIDE ( \_end = \_ebss );
/\* User\_heap\_stack section, used to check that there is enough RAM left \*/
.\_user\_heap\_stack :
{
. = ALIGN(4);
. = . + \_Min\_Heap\_Size;
. = . + \_Min\_Stack\_Size;
. = ALIGN(4);
} >RAM
/\* MEMORY\_bank1 section, code must be located here explicitly \*/
/\* Example: extern int foo(void) \_\_attribute\_\_ ((section (".mb1text"))); \*/
.memory\_b1\_text :
{
\*(.mb1text) /\* .mb1text sections (code) \*/
\*(.mb1text\*) /\* .mb1text\* sections (code) \*/
\*(.mb1rodata) /\* read-only data (constants) \*/
\*(.mb1rodata\*)
} >MEMORY\_B1
/\* Remove information from the standard libraries \*/
/DISCARD/ :
{
libc.a ( \* )
libm.a ( \* )
libgcc.a ( \* )
}
}
首先我们看ld文件的第一部分:
/\* Entry Point \*/
ENTRY(Reset\_Handler)
/\* Highest address of the user mode stack \*/
\_estack = 0x20010000; /\* end of 64K RAM \*/
/\* Generate a link error if heap and stack don't fit into RAM \*/
\_Min\_Heap\_Size = 0; /\* required amount of heap \*/
\_Min\_Stack\_Size = 0x200; /\* required amount of stack \*/
该部分指定了入口地址,RAM的结束地址。并指定了堆和栈的大小。
其中,Reset_Handler为入口地址。
因为我们实例中使用的MCU为STM32F103ZET6,其中RAM的大小为64K,RAM的启始地址为0x20000000,所以RAM的结束地址为:RAM启始地址+RAM的大小,即0x20010000。
堆的大小为0,即_Min_Heap_size=0;栈的大小为512B,即_Min_Stack_Size=0x200。
第二部分:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
MEMORY\_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
}
该部分给出地址的划分区间。
其中,FLASH的启始地址为0x08000000,其长度为512K。
RAM的启始地址为0x20000000,其长度为64K
MEMORY_B1的启始地址为0x60000000,其长度为0。
第三部分:
SECTIONS
{
/\* The startup code goes first into FLASH \*/
.isr\_vector :
{
. = ALIGN(4);
KEEP(\*(.isr\_vector)) /\* Startup code \*/
. = ALIGN(4);
} >FLASH
/\* The program code and other data goes into 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 \*/
KEEP (\*(.init))
KEEP (\*(.fini))
. = ALIGN(4);
\_etext = .; /\* define a global symbols at end of code \*/
} >FLASH
.ARM.extab : { \*(.ARM.extab\* .gnu.linkonce.armextab.\*) } >FLASH
.ARM : {
\_\_exidx\_start = .;
\*(.ARM.exidx\*)
\_\_exidx\_end = .;
} >FLASH
.ARM.attributes : { \*(.ARM.attributes) } > FLASH
.preinit\_array :
{
PROVIDE\_HIDDEN (\_\_preinit\_array\_start = .);
KEEP (\*(.preinit\_array\*))
PROVIDE\_HIDDEN (\_\_preinit\_array\_end = .);
} >FLASH
.init\_array :
{
PROVIDE\_HIDDEN (\_\_init\_array\_start = .);
KEEP (\*(SORT(.init\_array.\*)))
KEEP (\*(.init\_array\*))
PROVIDE\_HIDDEN (\_\_init\_array\_end = .);
} >FLASH
.fini\_array :
{
PROVIDE\_HIDDEN (\_\_fini\_array\_start = .);
KEEP (\*(.fini\_array\*))
KEEP (\*(SORT(.fini\_array.\*)))
PROVIDE\_HIDDEN (\_\_fini\_array\_end = .);
} >FLASH
/\* used by the startup to initialize data \*/
\_sidata = .;
/\* Initialized data sections goes into RAM, load LMA copy after code \*/
.data : AT ( \_sidata )
{
. = ALIGN(4);
\_sdata = .; /\* create a global symbol at data start \*/
\*(.data) /\* .data sections \*/
\*(.data\*) /\* .data\* sections \*/
. = ALIGN(4);
\_edata = .; /\* define a global symbol at data end \*/
} >RAM
/\* Uninitialized data section \*/
. = ALIGN(4);
.bss :
{
/\* This is used by the startup in order to initialize the .bss secion \*/
\_sbss = .; /\* define a global symbol at bss start \*/
\_\_bss\_start\_\_ = \_sbss;
\*(.bss)
\*(.bss\*)
\*(COMMON)
. = ALIGN(4);
\_ebss = .; /\* define a global symbol at bss end \*/
\_\_bss\_end\_\_ = \_ebss;
} >RAM
PROVIDE ( end = \_ebss );
PROVIDE ( \_end = \_ebss );
/\* User\_heap\_stack section, used to check that there is enough RAM left \*/
.\_user\_heap\_stack :
{
. = ALIGN(4);
. = . + \_Min\_Heap\_Size;
. = . + \_Min\_Stack\_Size;
. = ALIGN(4);
} >RAM
/\* MEMORY\_bank1 section, code must be located here explicitly \*/
/\* Example: extern int foo(void) \_\_attribute\_\_ ((section (".mb1text"))); \*/
.memory\_b1\_text :
{
\*(.mb1text) /\* .mb1text sections (code) \*/
\*(.mb1text\*) /\* .mb1text\* sections (code) \*/
\*(.mb1rodata) /\* read-only data (constants) \*/
\*(.mb1rodata\*)
} >MEMORY\_B1
/\* Remove information from the standard libraries \*/
/DISCARD/ :
{
libc.a ( \* )
libm.a ( \* )
libgcc.a ( \* )
}
}
该部分指定了程序的各个内容该如何放置在flash上或者ram上。
其中.=ALLGN(4)是指4字节对齐
.,小数点表示当前的地址位置
一般的程序中包含常见的几个段:text(存放程序),rodata(存放被初始化的数据),data(表示初始化不为0的变量),bass(表示初始化值为默认的全局变量)
Text,rodata放在FLASH中,而data中的初始化值作为rodata放在FLASH中,变量在RAM中占有空间,bss点RAM空间
段可以自定义,由于编译obj的过程中不会生成用户自定义的段,因此在源码中需要指定需要特殊处理的段
结尾的>MEMORY_B1指上面花括号内的内容都放在第二部分中定义的MEMORY_B1空间中。如果没有AT> FLASH,那么编译bin文件时,地址是连续的。