ld链接文件解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
.flash_contents 0x6000004C : AT (0x6000004C)
{
_mtext = .;
. = . + (_text_end - _text_start);
_mdummy = .;
. = . + (_dummy_end - _dummy_start);
_mdata = .;
. = . + (_data_end - _data_start);
flash_contents_end = .;
} > xSPI0_CS0_SPACE
.text 0x00102000 : AT (_mtext)
{
_text_start = .;

_fvector_start = .;
KEEP(*(.intvec))
_fvector_end = .;

_dummy_start = .;
KEEP(*(.dummy));
_dummy_end = .;


*(.text*)

KEEP(*(.reset_handler))
KEEP(*(.init))
KEEP(*(.fini))

/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
_ctor_end = .;

/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
_dtor_end = .;

KEEP(*(.eh_frame*))
} > RAM

1
.flash_contents 0x6000004C : AT (0x6000004C)

这里左边的0x6000004C是虚拟地址,是运行时的地址。右边的0x6000004C是加载地址,从右边的0x6000004C加载到左边的0x6000004C。

1
.text 0x00102000 : AT (_mtext)

如上解释,0x00102000是虚拟地址,这里是RAM地址,右边的AT (_mtext) 表示从mtext地址加载到0x00102000,而 _mtext 就是在 flash_contents 分配的

1
2
*(.text*)
*(.init)

第一个 * 表示包括所有括号里面的段,第二个 * 表示 .text 开头的所有子段

1
KEEP(*(.intvec))

类似于c语言的volatile关键字
没有使用 KEEP 指令,链接器在进行链接操作时,会依据其默认的垃圾回收机制(garbage collection)来处理节。当链接器认为某个节在最终的可执行文件中没有被引用时,就会将其丢弃,也就是不包含在最终的输出文件里。当使用 KEEP(*(.reset_handler)) 时,KEEP 指令会告知链接器,无论这个节是否被其他部分引用,都要强制将其保留在最终的可执行文件中。也就是说,链接器不会对 KEEP 所指定的节执行垃圾回收操作。
在 .reset_handler 节的场景中,复位处理函数对于系统的启动至关重要,无论链接器是否能检测到它的引用,都必须确保该节被包含在最终的可执行文件里。使用 KEEP 指令可以保证 .reset_handler 节中的复位处理函数代码被正确地链接到最终的程序中,从而确保系统在复位时能够正常启动。

1
2
3
4
5
6
7
8
.heap (NOLOAD) :
{
. = ALIGN(8);
__HeapBase = .;
/* Place the STD heap here. */
KEEP(*(.heap))
__HeapLimit = .;
} > SYSTEM_RAM

(NOLOAD)属性表示不把该段加载进固件