其他分享
首页 > 其他分享> > RISC-V MCU ld链接脚本说明

RISC-V MCU ld链接脚本说明

作者:互联网

1、什么是ld链接脚本?

通常,程序编译的最后一步就是链接,此过程根据“*.ld”链接文件将多个目标文件(.o)和库文件(.a)输入文件链接成一个可执行输出文件(.elf)。涉及到对空间和地址的分配以及符号解析与重定位

而ld链接脚本控制这整个链接过程,主要用于规定各输入文件中的程序、数据等内容段在输出文件中的空间和地址如何分配。通俗的讲,链接脚本用于描述输入文件中的段,将其映射到输出文件中,并指定输出文件中的内存分配。

 

2、ld链接脚本的主要内容

2.1 链接配置(可选)

常见的配置有入口地址、输出格式、符号变量的定义等。如:

1 ENTRY( _start ) /* 入口地址 */
2 
3   __stack_size = 2048; /* 定义栈大小 */
4 PROVIDE( _stack_size = __stack_size );/* 定义_stack_size符号,类似于全局变量 */

2.2 内存布局定义

对MCU的Flash及RAM空间进行分配,其中以ORIGIN定义地址空间的起始地址,LENGTH定义地址空间的长度。

语法如下:

1 MEMORY
2 {
3     name[(attr)] : ORIGIN = origin, LENGTH = length
4     ...
5 }

这里的attr只能由以下特性组成

'R' - Read-only section

'W' - Read/write section

'X' - Executable section

'A' - Allocatable section

'I' - Initialized section

'L' - Same as I

'!' - Invert the sense of any of the attributes that follow

2.3 段链接定义

用于定义目标文件(.o)textdatabss等段的链接分布。语法如下:

 1 SECTIONS
 2 {
 3     section [address] [(type)] :
 4     [AT(lma)]
 5     [ALIGN(section_align) | ALIGN_WITH_INPUT]
 6     [SUBALIGN(subsection_align)]
 7     [constraint]
 8     {
 9         output-section-command
10         output-section-command
11         ...
12     } [>region] [AT>lma_region] [:phdr :phdr ...] [=fillexp] [,]
13     
14     ...
15 }
16  
17 /* 大多数的段仅使用了上述部分属性,可以简写成如下形式 */
18 SECTIONS
19 {
20       ...
21       secname :
22       { 
23         output-section-command 
24       } 
25       ...
26 }

链接脚本本质就是描述输入和输出。secname表示输出文件的段,而output-section-command用来描述输出文件的这个段从哪些文件里抽取而来,即输入目标文件(.o)和库文件(.a)

Section 分为loadable(可加载)和allocatable(可分配)两种类型。不可加载也不可分配的内存段,通常包含一些调试等信息。
loadable:程序运行时,该段应该被加载到内存中。
allocatable:该段内容被预留出,同时不应该加载任何其他内容(某些情况下,这些内存必须归零)。

loadable和allocatable的section都有两个地址:"VMA"和"LMA"。
VMA (the vortual memory address):运行输出文件时,该section的地址。可选项,可不配置。
LAM (load memory address):加载section时的地址。
在大多数情况下,这两个地址时相同的。但有些情况下,需将代码从Flash中加载至RAM运行,此时Flash地址为LAM,RAM地址为VMA。如:

 1 .data :
 2     {
 3         *(.data .data.*)
 4         . = ALIGN(8);
 5         PROVIDE( __global_pointer$ = . + 0x800 );
 6         *(.sdata .sdata.*)
 7         *(.sdata2.*)
 8         . = ALIGN(4);
 9         PROVIDE( _edata = .);
10    } >RAM AT>FLASH

上述示例中,.data段的内容会放在Flash中,但是运行时,会加载至RAM中(通常为初始化全局变量),即.data段的VMA为RAM,LMA为Flash

3、常用关键字及命令

3.1 ENTRY

语法:ENTRY(symbol),程序中要执行的第一个指令,也称入口点。示例:

1 /* Entry Point */
2 ENTRY( _start ) /* CH32V103为启动文件 j handle_reset 指令*/

3.2 PROVIDE

语法:PROVIDE (symbol = expression),用于定义一个可被引用的符号,类似于全局变量。示例:

1 PROVIDE( end = . ); 

3.3 HIDDEN

语法:HIDDEN (symbol = expression),对于ELF目标端口,符号将被隐藏且不被导出。示例:

1 HIDDEN (mySymbol = .);

3.4 PROVIDE_HIDDEN

语法:PROVIDE_HIDDEN (symbol = expression),是PROVIDE 和HIDDEN的结合体,类似于局部变量。示例:

1 PROVIDE_HIDDEN (__preinit_array_start = .);

3.5 点位符号 '.'

‘.’表示当前地址,它是一个变量,总是代表输出文件中的一个地址(根据输入文件section的大小不断增加,不能倒退,且只用于SECTIONS指令中)。它可以被赋值也可以赋值给某个变量;也可进行算术运算用于产生指定长度的内存空间。示例:

1 PROVIDE( end = . );   /* 当前地址赋值给 end符号 */
2  
3 .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size :
4 {
5     . = ALIGN(4); 
6     PROVIDE(_susrstack = . );
7     . = . + __stack_size;    /* 当前地址加上__stack_size长度,产生__stack_size长度的空间*/
8     PROVIDE( _eusrstack = .);
9 } >RAM 

3.6 KEEP

当链接器使用('--gc-sections')进行垃圾回收时,KEEP()可以使得被标记段的内容不被清楚。示例

1 .init :
2 {
3     _sinit = .;
4     . = ALIGN(4);
5     KEEP(*(SORT_NONE(.init))) 
6     . = ALIGN(4);
7     _einit = .;
8 } >FLASH AT>FLASH

3.7 ASSERT

语法:ASSERT(exp, message),确保exp是非零值,如果为零,将以错误码的形式退出链接文件,并输出message。主要用于添加断言,定位问题。

示例:

 1 /* The usage of ASSERT */
 2 PROVIDE (__stack_size = 0x100);
 3  
 4 .stack
 5 {
 6     PROVIDE (__stack = .);
 7     ASSERT ((__stack > (_end + __stack_size)), "Error: No room left for the stack");
 8 }
 9 /* 当"__stack" 大于 "_end + __stack_size"时,在链接时,会出现错误,并提示"Error: No room left for the stack" */
10  

4、完整ld链接脚本示例

以RISC-V MCU CH32V103为例。

  1 ENTRY( _start )  
  2  
  3 __stack_size = 2048;
  4  
  5 PROVIDE( _stack_size = __stack_size );
  6  
  7  
  8 MEMORY
  9 {
 10   FLASH (rx) : ORIGIN = 0x00000000 , LENGTH = 0x10000
 11   RAM (xrw) : ORIGIN = 0x20000000 , LENGTH = 0x5000
 12 }
 13  
 14  
 15 SECTIONS
 16 {
 17  
 18     .init :
 19     {
 20         _sinit = .;
 21         . = ALIGN(4);
 22         KEEP(*(SORT_NONE(.init)))
 23         . = ALIGN(4);
 24         _einit = .;
 25     } >FLASH AT>FLASH
 26  
 27   .vector :
 28   {
 29       *(.vector);
 30       . = ALIGN(64);
 31   } >FLASH AT>FLASH
 32  
 33   .flag :
 34   {
 35       . = ORIGIN(FLASH)+0x8000;
 36       KEEP(*(SORT_NONE(.myBufSection)))
 37   }>FLASH AT>FLASH
 38  
 39     .text :
 40     {
 41         . = ALIGN(4);
 42         *(.text)
 43         *(.text.*)
 44         *(.rodata)
 45         *(.rodata*)
 46         *(.glue_7)
 47         *(.glue_7t)
 48         *(.gnu.linkonce.t.*)
 49         . = ALIGN(4);
 50     } >FLASH AT>FLASH 
 51  
 52     .fini :
 53     {
 54         KEEP(*(SORT_NONE(.fini)))
 55         . = ALIGN(4);
 56     } >FLASH AT>FLASH
 57  
 58     PROVIDE( _etext = . );
 59     PROVIDE( _eitcm = . );    
 60  
 61     .preinit_array  :
 62     {
 63       PROVIDE_HIDDEN (__preinit_array_start = .);
 64       KEEP (*(.preinit_array))
 65       PROVIDE_HIDDEN (__preinit_array_end = .);
 66     } >FLASH AT>FLASH 
 67     
 68     .init_array     :
 69     {
 70       PROVIDE_HIDDEN (__init_array_start = .);
 71       KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
 72       KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
 73       PROVIDE_HIDDEN (__init_array_end = .);
 74     } >FLASH AT>FLASH 
 75     
 76     .fini_array     :
 77     {
 78       PROVIDE_HIDDEN (__fini_array_start = .);
 79       KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
 80       KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
 81       PROVIDE_HIDDEN (__fini_array_end = .);
 82     } >FLASH AT>FLASH 
 83     
 84     .ctors          :
 85     {
 86       /* gcc uses crtbegin.o to find the start of
 87          the constructors, so we make sure it is
 88          first.  Because this is a wildcard, it
 89          doesn't matter if the user does not
 90          actually link against crtbegin.o; the
 91          linker won't look for a file to match a
 92          wildcard.  The wildcard also means that it
 93          doesn't matter which directory crtbegin.o
 94          is in.  */
 95       KEEP (*crtbegin.o(.ctors))
 96       KEEP (*crtbegin?.o(.ctors))
 97       /* We don't want to include the .ctor section from
 98          the crtend.o file until after the sorted ctors.
 99          The .ctor section from the crtend file contains the
100          end of ctors marker and it must be last */
101       KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
102       KEEP (*(SORT(.ctors.*)))
103       KEEP (*(.ctors))
104     } >FLASH AT>FLASH 
105     
106     .dtors          :
107     {
108       KEEP (*crtbegin.o(.dtors))
109       KEEP (*crtbegin?.o(.dtors))
110       KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
111       KEEP (*(SORT(.dtors.*)))
112       KEEP (*(.dtors))
113     } >FLASH AT>FLASH 
114  
115     .dalign :
116     {
117         . = ALIGN(4);
118         PROVIDE(_data_vma = .);
119     } >RAM AT>FLASH    
120  
121     .dlalign :
122     {
123         . = ALIGN(4); 
124         PROVIDE(_data_lma = .);
125     } >FLASH AT>FLASH
126  
127     .data :
128     {
129         *(.gnu.linkonce.r.*)
130         *(.data .data.*)
131         *(.gnu.linkonce.d.*)
132         . = ALIGN(8);
133         PROVIDE( __global_pointer$ = . + 0x800 );
134         *(.sdata .sdata.*)
135         *(.sdata2.*)
136         *(.gnu.linkonce.s.*)
137         . = ALIGN(8);
138         *(.srodata.cst16)
139         *(.srodata.cst8)
140         *(.srodata.cst4)
141         *(.srodata.cst2)
142         *(.srodata .srodata.*)
143         . = ALIGN(4);
144         PROVIDE( _edata = .);
145     } >RAM AT>FLASH
146  
147     .bss :
148     {
149         . = ALIGN(4);
150         PROVIDE( _sbss = .);
151           *(.sbss*)
152         *(.gnu.linkonce.sb.*)
153         *(.bss*)
154          *(.gnu.linkonce.b.*)        
155         *(COMMON*)
156         . = ALIGN(4);
157         PROVIDE( _ebss = .);
158     } >RAM AT>FLASH
159  
160     PROVIDE( _end = _ebss);
161     PROVIDE( end = . );
162  
163     .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size :
164     {
165         . = ALIGN(4);
166         PROVIDE(_susrstack = . );
167         . = . + __stack_size;
168         PROVIDE( _eusrstack = .);
169     } >RAM 
170  
171 }

 

标签:__,ld,PROVIDE,ALIGN,FLASH,RISC,KEEP,MCU,stack
来源: https://www.cnblogs.com/Zhuzzz/p/16293250.html