__early_initcall_end = .;
*(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s.init) *(.initcall3.init) *(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init)
__initcall_end = .;
__con_initcall_start = .;
*(.con_initcall.init)
__con_initcall_end = .;
__security_initcall_start = .;
*(.security_initcall.init)
__security_initcall_end = .;
. = ALIGN(32);//ALIGN,表示对齐,即这里的Location Counter的位置必须按32对齐
__initramfs_start = .; //ramfs的位置
usr/built-in.o(.init.ramfs)
__initramfs_end = .;
. = ALIGN(4096); //4K对齐
__per_cpu_load = .;
__per_cpu_start = .;
*(.data.percpu.page_aligned)
*(.data.percpu)
*(.data.percpu.shared_aligned)
__per_cpu_end = .;
__init_begin = _stext;
*(.init.data) *(.cpuinit.data) *(.cpuinit.rodata) *(.meminit.data) *(.meminit.rodata)
. = ALIGN(4096);
__init_end = .;
}
//DISACARD是一个特殊的section,表示符合这个条件的输入段都不会写到输出段中,也就是输出文件中不包含下列段
/DISCARD/ : { /* Exit code and data */
*(.exit.text) *(.cpuexit.text) *(.memexit.text)
*(.exit.data) *(.cpuexit.data) *(.cpuexit.rodata) *(.memexit.data) *(.memexit.rodata)
*(.exitcall.exit)
*(.ARM.exidx.exit.text)
*(.ARM.extab.exit.text)
}
//省略部分内容
//ADDR为内置函数,用来返回VMA的
/*
这里举个小例子,大家看看VMA和LMA到底有什么作用
SECTIONS
{
.text 0x1000 : { *(.text) _etext = . ; } /.text段的VMA为0x1000,而且LMA=VMA
.mdata 0x2000 : //.mdata段的VMA为0x2000,但是它的LMA却在.text段的结尾
AT ( ADDR (.text) + SIZEOF (.text) )
{ _data = . ; *(.data); _edata = . ; }
.bss 0x3000 :
{ _bstart = . ; *(.bss) *(COMMON) ; _bend = . ;}
}
看到了么?.mdata段运行的时候在0x2000,但是数据load地址却在.text段后,所以运行的时候需要把.mdata段内容拷贝过去。
extern char _etext, _data, _edata, _bstart, _bend;
char *src = &_etext; //_etext为.text端的末尾 VMA地址,但同时也是.mdata段LMA的开始,有LS种的AT指定
char *dst = &_data; //_data为mdata段的VMA,现在需要把LMA地址开始的内容拷贝到VMA开始的地方
/* ROM has data at end of text; copy it. */
while (dst < &_edata)
*dst++ = *src++; //拷贝....明白了?不明白的好好琢磨
/* Zero bss. */
for (dst = &_bstart; dst< &_bend; dst++)
*dst = 0; //初始化数据区域
*/
.rodata : AT(ADDR(.rodata) - 0) {
__start_rodata = .;
*(.rodata) *(.rodata.*) *(__vermagic) *(__markers_strings) *(__tracepoints_strings)
}
.rodata1 : AT(ADDR(.rodata1) - 0) {
*(.rodata1)
}
......//省略部分内容
_edata_loc = __data_loc + SIZEOF(.data);
.bss : {
__bss_start = .; /* BSS */
*(.bss)
*(COMMON)
_end = .;
}
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
}
//ASSERT是命令,如果第一个参数为0,则打印第二个参数的信息(也就是错误信息),然后ld命令退出。
ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support")
ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")
五 内核代码中使用LS中定义的变量
咱们看一个小例子
[-->init/main.c]
extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[]; //这几个值在LS中定义。大家可以在上面搜索下