Linux内核启动start_kernel之前逻辑分析(汇编)

阅读数:139 评论数:0

跳转到新版页面

分类

Linux

正文

在bootloader的帮助下,内核被载入到内存中,内核映像被加载到内存并获得控制权之后,内核启动流程开始。通常,内核映像以压缩形式存储,并不是一个可以执行的内核。因此内核的首要工作是自解压内核映像。

内核编译生成vmlinux后,通常会对其进行压缩,得到zImage(小内核,小于512KB)或者bzImage(大内核,大于512KB),在它们的头部嵌有解压缩程序真正的内核执行映像其实是在编译时生arch/${ARCH}/boot/文件夹中的bin文件

以arm为例

Linxu镜像的格式:

(1)Image:直接生成并未压缩的内核,一般用于PC机。

(2)zImage:Image的压缩版,采用gzip进行压缩,比Image体积小,但启动时需要进行自解压,嵌入式系统中一般采用此方法。

(3)uImage:是u-boot专用的一种内核镜像格式,它是在zImage的基础上又添加了一个长度为0x40的标签头,在u-boot启动时会去掉此头信息,仍按zImage启动,头信息主要用于区分不同格式的内核镜像。

(4)xipImage:片上执行的未压缩内核

(5)bootpImage:将内核与根文件系统制作在一起的镜像。

 

内核的压缩和解压缩代码都在文件夹arch/arm/boot/compressed下,编译完毕后将产生head.o, misc.o , piggy.gzip.o, vmlinux, decompress.o这几个文件。

(1)head.o是内核的头部文件,负责初始设置。

(2)misc.o将主要负责内核的解压工作。

(3)piggy.gzip.o是一个压缩的内核(kernel/vmlinux)

(4)vmlinux是没有(zImage是压缩过后内核)压缩过的内核。它是由piggy.gzip、head.o、misc.o组成的。

(5)decompress.o是为支持很多其它的压缩格式而新引入的。

压缩过的kernel入口第一个源代码位置在arch/arm/boot/compressed/head.S,它将调用函数decompress_kernel(),这个函数在arch/arm/boot/compressed/misc.c中。decompress_kernel又调用arch_decomp_setup进行设置,decompress_kernel又调用gunzip()将内核放于指定的位置。

而gunzip位于kernel/lib/inflate.c, inflate.c是从gzip源程序中分离出来的,

 

启动流程分析:

1、通过linux/arch/arm/boot/compressed目录下的Makefile寻找到下面代码段:

$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o \
$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) \
$(bswapsdi2) $(efi-obj-y) FORCE
@$(check_for_multiple_zreladdr)
$(call if_changed,ld)
@$(check_for_bad_syms)

2、从这里我们可以得知链接脚本vmlinux.lds,所以分析vmlinux.lds,根据其中ENTRY(stext)得到内核入口函数为stext,

面stext在linux/arch/arm/kernel/head.S中

3、head.S中内核引导阶段

ENTRY(stext)
。
。
。
bl __lookup_processor_type @ r5=procinfo r9=cpuid //处理器是否支持
movs r10, r5 @ invalid processor (r5=0)?
THUMB( it eq ) @ force fixup-able long branch encoding
beq __error_p @ yes, error 'p' //不支持则打印错误信息

。
。
。
bl __create_page_tables //创建页表

/*
* The following calls CPU specific code in a position independent
* manner. See arch/arm/mm/proc-*.S for details. r10 = base of
* xxx_proc_info structure selected by __lookup_processor_type
* above. On return, the CPU will be ready for the MMU to be
* turned on, and r0 will hold the CPU control register value.
*/
ldr r13, =__mmap_switched @ address to jump to after //保存MMU使能后跳转地址
@ mmu has been enabled
adr lr, BSYM(1f) @ return (PIC) address
mov r8, r4 @ set TTBR1 to swapper_pg_dir
ARM( add pc, r10, #PROCINFO_INITFUNC )
THUMB( add r12, r10, #PROCINFO_INITFUNC )
THUMB( mov pc, r12 )
1: b __enable_mmu

4、查找标签__mmap_switched所在位置:linux/arch/arm/kernel/head-common.S

__mmap_switched:
/*
* The following fragment of code is executed with the MMU on in MMU mode,
* and uses absolute addresses; this is not position independent.
*
* r0 = cp#15 control register
* r1 = machine ID
* r2 = atags/dtb pointer
* r9 = processor ID
*/
//保存设备信息、设备树及启动参数存储地址
。
。
。
b start_kernel

从start_kernel函数开始,内核进入C语言部分,完成内核大部分初始化工作。

vmlinux.lds.S

vmlinux.lds.S是如何组织内核的每个函数存放在内核镜像文件的位置,我们知道在编译内核生成内核文件的时候,其实这个过程分两步,一个是编译,另一个是链接,vmlinux.lds.S要做的就是告诉编译器如何链接编译好的各个内核.o文件。

小知识:链接器中的entry
链接器 按以下优先顺序设入口点,找到即停止
1. -e 命令行选项
2. 脚本中的entry(symbol)命令
3. 如定义了start的值,取其值为入口点
4. 如果存在.text section,使用.text section的第一字节的位置值
5. 使用值0

所以

OUTPUT_ARCH(arm)
ENTRY(stext)

表明我们指定的stext作为程序的入口点。

1、.=PAGE_OFFSET+TEXT_OFFSET

arch/arm/include/asm中的memory.h文件定义了:

#define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET)

CONFIG_PAGE_OFFSET是在内核配置里面配置的,PAGE_OFFSET代表的是内核image的起始虚拟地址,在arch/arm/Makefile中定义:

textofs-y := 0x00008000
TEXT_OFFSET := $(textofs-y)

TEXT_OFFSET代表的是内核的image存放在内存中地址,注意这个地址为相对内存的起始地址的偏移量,是个相对的偏移量不是实际的存放内存物理地址。而且这个偏移量必须为0xXXXX8000,XXXX为任意值。

2、简单例子

SECTIONS
{
. = 0×10000; /**把定位器符号置为0x10000(若不指定,则该符号的初始值为0)*/
.text : { *(.text) } /* 将所有输入文件的.text section合并成一个.text section,该section的地址由定位器符号的值指定*/
. = 0×8000000; /* 把定位器符号置为0x8000000*/
.data : { *(.data) } /* 将所有输入文件的.data section合并成一个.data section,该section的地址被置为0x8000000*/
.bss : { *(.bss) } /* 将所有输入文件的.bss section合并成一个.bss section,该section的地址被置为0x8000000+.data section的大小*/
/*连接器每读完一个section描述后,将定位器符号的值增加该section的大小,这里没有考虑对齐约束*/
}

.是一个特殊的符号,它是定位器,一个位置指针,指向程序地址空间内的某位置,该符号只能在SECTIONS命令内使用。

3、简单命令

INCLUDE filename: 包含其他名为filename的链接脚本,可以嵌套使用,最大深度为10
INPUT(files):将括号内的文件做为链接过程的输入文件。ld首先在当前目录下寻找该文件,如果没找到,则在由-L指定的搜索路径下搜索。
GROUP(files):指定需要重复搜索符号定义的多个输入文件。file必须是库文件,且file文件作为一组被ld重复扫描,直到不再有新的未定义的引用出现。
OUTPUT(filename):定义输出文件的名字。同ld的-o选项,不过-o选项的优先级更高。
SEARCH_DIR(path):定义搜索路径。同ld的-L选项,不过由-L指定的路径要比它定义的优先被搜索。
STARTUP(filename):指定filename为第一个输入文件
OUTPUT_FORMAT(DEFAULT,BIG,LITTLE):定义三种输出文件的格式,若有命令行选项-EB,则使用第2个BFD格式,若有命令行选项-EL,则使用第3鼐BFD格式,否则默认选第一个BFD格式。
TARGET(BFDNAME):设置输入文件的BFD格式。
ASSERT(EXP,MESSAGE):如果EXP不为真,终止连接过程
EXTERN(SYMBOL SYMBOL...):在输出文件中增加未定义的符号,如同连接器选项-u
FORCE_COMMON_ALLOCATION:为common symbol(通用符号)分配空间,即使用了-r连接选项也为其分配
NOCROSSREFS(SECTION SECTION...):检查列出的输出secion,如果发现他们之间有相互引用,则报错。对于某些系统,特别是内存较紧张的嵌入式系统,某些section是不能同时存在内存中的,所以他们之间不能相互引用
OUtPUT_ARCH(arch):设置输出文件的machine architecture

4、SECTIOINS命令

SECTIONS命令告诉ld如何把输入文件的sections映射到输出文件的各个section:如何将输入section合并为输出section,如何把输出section放入程序地址空间(VMA)和进程地址空间(LMA)。

(1)输出section描述

SECTION-NAME [ADDRESS] [(TYPE)] : [AT(LMA)]
{
OUTPUT-SECTION-COMMAND
OUTPUT-SECTION-COMMAND

} [>REGION] [AT>LMA_REGION] [:PHDR HDR ...] [=FILLEXP]

SECTION-NAME左右的空白、圆括号、冒号是必须的,ADDRESS是一个表达式,它的值用于设置VMA,如果没有该选项且有REGION选项,那么连接器将根据REGION设置VMA,哪果也没有REGION选项,那么连接器将根据定位符‘.’的值设置该section的VMA,将定位符号的值调整到满足输出section对齐要求后的值。

TYPE设置输出section的类型,如果没有指定TYPE类型,那么连接器根据输出section引用的输入section的类型设置该输出section类型。

默认情况下,LMA等于VMA,但可以通过AT(LMA)项画指定LMA。




相关推荐

重点:linux内核中的汇编基于AT&T的语法。 一、简介 Linux内核中包含的汇编源码主要由两部分组成:一大部分是内核arch目录和其它目录下的纯汇编文件,以.S为后缀的文件;另一小部分是嵌入在C

一、概述 1、为什么Linus不使用GPLv3 在 PC 上,只要你得到了某个程序的源代码,就可以自行编译生成二进制程序,然后替换掉原有的二进制程序,你的程序自由很容易得到保证。然而 iPod、iPh

说明:这种方式只是用于方便阅读代码,因为可以在源代间快速索引跳跃。但是最后可能会有一些warning,可以不必关心,如果是强迫症,可以使用下面这种方式来去掉。

一、概述 在Linux系统中,/usr/bin和/usr/local/bin是两个常见的目录,用于存放可执行文件(二进制文件)。 很多应用都安装在/usr/local下面,先看一下automake工具

  一、概述 vmstat命令是最常见的Linux/Unix监控工具,可以监控给定时间间隔服务器的CPU使用率、内存使用、IO情况。相比top命令,可以查看到整个机器的CPU、内存、IO的使用情况,而

一、概述 sar,System Activity Reporter。是目前 Linux 上最为全面的系统性能分析工具之一,可以从多方面对系统的活动进行报告,包括:文件的读写情况、系统调用的使用情况、磁

一、简介 简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。 二、使用方法 1、基本语法  awk '条件类型1 {动作1} 条件类型2{动作2} ...

一、概述 列出目标目录中所有的子目录和文件。 二、 语法 ls [选项] [目录名] -a, –all 列出目录下的所有文件,包括以 . 开头的隐含文件 -A 同-a,但不列出“.”(表示当前目录)

一、概述 cd全称是change directory,用于切换当前工作目录。 注意的是,cd命令是一个内建命令,它是由 shell 提供的。因此,不同的 shell 可能会有一些差异,但基本的用法和功

一、概述 全称为print working directory,查看”当前工作目录“的完整路径,一般情况下不带任何参数 二、语法 pwd [选项] -L 即logical,逻辑路径 -P 即