以linux内核启动地址破解30008000由来之谜

时间:2011-09-02

关于Linux

  Linux是一类Unix计算机操作系统的统称。Linux操作系统的内核的名字也是“Linux”。Linux操作系统也是自由软件和开放源代码发展中着名的例子。严格来讲,Linux这个词本身只表示Linux内核,但在实际上人们已经习惯了用Linux来形容整个基于Linux内核,并且使用GNU 工程各种工具和数据库的操作系统。Linux得名于计算机业余爱好者Linus Torvalds。

内核概念解说

  在Linux的术语中被称为“内核”,也可以称为“”。Linux内核的主要模块(或组件)分以下几个部分:存储管理、CPU和进程管理、文件系统、设备管理和驱动、网络通信,以及系统的初始化(引导)、系统调用等。Linux 内核实现了很多重要的体系结构属性。在或高或低的层次上,内核被划分为多个子系统。Linux 也可以看作是一个整体,因为它会将所有这些基本服务都集成到内核中。这与微内核的体系结构不同,后者会提供一些基本的服务,例如通信、I/O、内存和进程管理,更具体的服务都是插入到微内核层中的。

内核启动地址的分析过程:

 内核编译链接过程是依靠vmlinux.lds文件,以arm为例vmlinux.lds文件位于kernel/arch/arm/vmlinux.lds,

  vmlinux-armv.lds的生成过程在kernel/arch/arm/Makefile中

  ifeq ($(CONFIG_CPU_32),y)

  PROCESSOR = armv

  TEXTADDR = 0xC0008000

  LDSCRIPT = arch/arm/vmlinux-armv.lds.in

  endif

  arch/arm/vmlinux.lds: $(LDSCRIPT) dummy

  @sed 's/TEXTADDR/$(TEXTADDR)/;s/DATAADDR/$(DATAADDR)/' $(LDSCRIPT) >$@

  查看arch/arm/vmlinux.lds 中

  OUTPUT_ARCH(arm)

  ENTRY(stext)

  SECTIONS

  {

  . = 0xC0008000;

  .init : { /* Init code and data */

  _stext = .;

  __init_begin = .;

  *(。text.init)

  __proc_info_begin = .;

  *(。proc.info)

  __proc_info_end = .;

  __arch_info_begin = .;

  *(。arch.info)

  __arch_info_end = .;

  __tagtable_begin = .;

  *(。taglist)

  __tagtable_end = .;

  *(。data.init)

  . = ALIGN(16);

  __setup_start = .;

  *(。setup.init)

  __setup_end = .;

  __initcall_start = .;

  *(。initcall.init)

  __initcall_end = .;

  . = ALIGN(4096);

  __init_end = .;

  }

  /DISCARD/ : { /* Exit code and data */

  *(。text.exit)

  *(。data.exit)

  *(。exitcall.exit)

  }

  .text : { /* Real text segment */

  _text = .; /* Text and read-only data */

  *(。text)

  *(。fixup)

  *(。gnu.warning)

  *(。rodata)

  *(。rodata.*)

  *(。glue_7)

  *(。glue_7t)

  *(。got) /* Global offset table */

  _etext = .; /* End of text section */

  }

  .kstrtab : { *(。kstrtab) }

  . = ALIGN(16);

  __ex_table : { /* Exception table */

  __start___ex_table = .;

  *(__ex_table)

  __stop___ex_table = .;

  }

  __ksymtab : { /* Kernel symbol table */

  __start___ksymtab = .;

  *(__ksymtab)

  __stop___ksymtab = .;

  }

  . = ALIGN(8192);

  .data : {

  /*

  * fIRst, the init task union, aligned

  * to an 8192 byte boundary.

  */

  *(。init.task)

  /*

  * then the cacheline aligned data

  */

  . = ALIGN(32);

  *(。data.cacheline_aligned)

  /*

  * and the usual data section

  */

  *(。data)

  CONSTRUCTORS

  _edata = .;

  }

  .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) }

  }

  arch/arm/Makefile中:

  vmlinux: arch/arm/vmlinux.lds

  arch/arm/vmlinux.lds: $(LDSCRIPT) dummy

  @sed 's/TEXTADDR/$(TEXTADDR)/;s/DATAADDR/$(DATAADDR)/' $(LDSCRIPT) >$@

  MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot

  bzImage zImage zinstall Image bootpImage install: vmlinux

  @$(MAKEBOOT) $@

  但在kernel/arch/arm/boot/Makefile

  ifeq ($(CONFIG_ARCH_S3C2410),y)

  ZTEXTADDR = 0x30008000

  ZRELADDR = 0x30008000

  endif

  zImage: $(CONFIGURE) compressed/vmlinux

  $(OBJCOPY) -O binary -R .note -R .comment -S compressed/vmlinux $@

  compressed/vmlinux: $(TOPDIR)/vmlinux dep

  @$(MAKE) -C compressed vmlinux

  在compressed目录下的Makefile中

  ZLDFLAGS = -p -X -T vmlinux.lds

  SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;s/BSS_START/$(ZBSSADDR)/

  all: vmlinux

  vmlinux: $(HEAD) $(OBJS) piggy.o vmlinux.lds

  $(LD) $(ZLDFLAGS) $(HEAD) $(OBJS) piggy.o $(LIBGCC) -o vmlinux

  vmlinux.lds: vmlinux.lds.in Makefile $(TOPDIR)/arch/$(ARCH)/boot/Makefile $(TOPDIR)/.config

  @sed "$(SEDFLAGS)" < vmlinux.lds.in > $@

  vmlinux-armv.lds.in文件的内容:

  OUTPUT_ARCH(arm)

  ENTRY(_start)

  SECTIONS

  {

  . = LOAD_ADDR;

  _load_addr = .;

  . = TEXT_START;

  _text = .;

  .text : {

  _start = .;

  *(。start)

  *(。text)

  *(。fixup)

  *(。gnu.warning)

  *(。rodata)

  *(。rodata.*)

  *(。glue_7)

  *(。glue_7t)

  input_data = .;

  piggy.o

  input_data_end = .;

  . = ALIGN(4);

  }

  _etext = .;

  _got_start = .;

  .got : { *(。got) }

  _got_end = .;

  .got.plt : { *(。got.plt) }

  .data : { *(。data) }

  _edata = .;

  . = BSS_START;

  __bss_start = .;

  .bss : { *(。bss) }

  _end = .;

  .stack (NOLOAD) : { *(。stack) }

  .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) }

  }

  vmlinux.lds内容为

  OUTPUT_ARCH(arm)

  ENTRY(_start)

  SECTIONS

  {

  . = 0x30008000;

  _load_addr = .;

  . = 0;

  _text = .;

  .text : {

  _start = .;

  *(。start)

  *(。text)

  *(。fixup)

  *(。gnu.warning)

  *(。rodata)

  *(。rodata.*)

  *(。glue_7)

  *(。glue_7t)

  input_data = .;

  piggy.o

  input_data_end = .;

  . = ALIGN(4);

  }

  _etext = .;

  _got_start = .;

  .got : { *(。got) }

  _got_end = .;

  .got.plt : { *(。got.plt) }

  .data : { *(。data) }

  _edata = .;

  . = ALIGN(4);

  __bss_start = .;

  .bss : { *(。bss) }

  _end = .;

  .stack (NOLOAD) : { *(。stack) }

  .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) }

  }

  一般情况下都在生成vmlinux后,再对内核进行压缩成为zImage,压缩的目录是kernel/arch/arm/boot。

  到flash中的是压缩后的zImage文件,zImage是由压缩后的vmlinux和解压缩程序组成,如下图所示:

  |-----------------|\ |-----------------|

  | | \ | |

  | | \ | decompress code |

  | vmlinux | \ |-----------------| zImage

  | | \| |

  | | | |

  | | | |

  | | | |

  | | /|-----------------|

  | | /

  | | /

  | | /

  |-----------------|/

  zImage链接脚本也叫做vmlinux.lds,位于kernel/arch/arm/boot/compressed。

  是由同一目录下的vmlinux.lds.in文件生成的

  在kernel/arch/arm/boot/Makefile文件中定义了:

  ifeq ($(CONFIG_ARCH_S3C2410),y)

  ZTEXTADDR = 0x30008000

  ZRELADDR = 0x30008000

  endif

  ZTEXTADDR就是解压缩代码的ram偏移地址,ZRELADDR是内核ram启动的偏移地址,这里看到指定ZTEXTADDR的地址为30008000,

总结内核启动地址的设置:

  设置kernel/arch/arm/boot/Makefile文件中的

  ifeq ($(CONFIG_ARCH_S3C2410),y)

  ZTEXTADDR = 0x30008000

  ZRELADDR = 0x30008000

  endif

  # We now have a PIC decompressor implementation. Decompressors running

  # from RAM should not define ZTEXTADDR. Decompressors running directly

  # from ROM or Flash must define ZTEXTADDR (preferably via the config)

  #

  查看2410的datasheet ,发现内存映射的基址是0x3000 0000 ,那么 0x30008000又是如何来的呢?

  在内核文档kernel/Document/arm/Booting 文件中有:

  Calling the kernel image

  Existing boot loaders: MANDATORY

  New boot loaders: MANDATORY

  There are two options for calling the kernel zImage. If the zImage is stored in flash, and is linked correctly to be run from flash, then it is legal for the boot loader to call the zImage in flash directly.

  The zImage may also be placed in system RAM (at any location) and called there. Note that the kernel uses 16K of RAM below the image to store page tables. The recommended placement is 32KiB into RAM.

  看来在image下面用了32K(0x8000)的空间存放内核页表,

  0x30008000就是2410的内核在RAM中的启动地址,这个地址就是这么来的。



  
上一篇:WINCE快捷方式详细介绍
下一篇:IDT提供企业级方案为Intel Xeon处理器

免责声明: 凡注明来源本网的所有作品,均为本网合法拥有版权或有权使用的作品,欢迎转载,注明出处。非本网作品均来自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

相关技术资料