Linux Kernel系列三:Kernel编译和链接中的linker scr(4)

__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中定义。大家可以在上面搜索下

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/46606dcd6b9a27c58f98479a68d6551b.html