linux内核编译流程、驱动加载顺序

内核编译

根据顶层Makefile找到vmlinux目标开始分析:

vmlinux: scripts/link-vmlinux.sh autoksyms_recursive $(vmlinux-deps) FORCE
        +$(call if_changed,link-vmlinux)

vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_OBJS) $(KBUILD_VMLINUX_LIBS)

 根据这个展开 vmlinux-deps := arch/$(SRCARCH)/kernel/vmlinux.lds (head-y init-y core-y libs-y2 drivers-y net-y virt-y libs-y1)

# Externally visible symbols (used by link-vmlinux.sh)
export KBUILD_VMLINUX_OBJS := $(head-y) $(init-y) $(core-y) $(libs-y2) \
                              $(drivers-y) $(net-y) $(virt-y)
export KBUILD_VMLINUX_LIBS := $(libs-y1)
export KBUILD_LDS          := arch/$(SRCARCH)/kernel/vmlinux.lds

上面的xxxx-y就是,每个目录生成的各.o文件集合,会被打包成一个个built-in.a

ifeq ($(KBUILD_EXTMOD),)
# Objects we will link into vmlinux / subdirs we need to visit
init-y          := init/
drivers-y       := drivers/ sound/
drivers-$(CONFIG_SAMPLES) += samples/
net-y           := net/
libs-y          := lib/
core-y          := usr/
virt-y          := virt/
endif # KBUILD_EXTMOD

core-y          += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/

vmlinux-dirs    := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
                     $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
                     $(net-y) $(net-m) $(libs-y) $(libs-m) $(virt-y)))

vmlinux-alldirs := $(sort $(vmlinux-dirs) Documentation \
                     $(patsubst %/,%,$(filter %/, $(init-) $(core-) \
                        $(drivers-) $(net-) $(libs-) $(virt-))))

build-dirs      := $(vmlinux-dirs)
clean-dirs      := $(vmlinux-alldirs)

init-y          := $(patsubst %/, %/built-in.a, $(init-y))
core-y          := $(patsubst %/, %/built-in.a, $(core-y))
drivers-y       := $(patsubst %/, %/built-in.a, $(drivers-y))
net-y           := $(patsubst %/, %/built-in.a, $(net-y))
libs-y1         := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2         := $(patsubst %/, %/built-in.a, $(filter-out %.a, $(libs-y)))
virt-y          := $(patsubst %/, %/built-in.a, $(virt-y))

head-y = arch/arm/kernel/head.o

head-y 定义在文件 arch/arm/Makefile 中:
head-y := arch/arm/kernel/head$(MMUEXT).o

当不使能 MMU 的话 MMUEXT=-nommu,如果使能 MMU 的话为空,因此 head-y为: 
head-y = arch/arm/kernel/head.o

libs-y = arch/arm/lib/lib.a lib/lib.a arch/arm/lib/built-in.o lib/built-in.o

顶层Makefile中:libs-y          := lib/
在arch/arm/Makefile中,对libs-y又追加了: libs-y := arch/arm/lib/ $(libs-y) 展开后: libs-y = arch/arm/lib lib/ 


回到顶层Makefile:
libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
libs-y := $(libs-y1) $(libs-y2)

core-y = usr/built-in.o  kernel/built-in.o ...... arch/arm/crypto/built-in.o

顶层Makefile中:
core-y := usr/
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/


在 arch/arm/Makefile 中会对 core-y 进行追加,代码如下
core-$(CONFIG_FPE_NWFPE)        += arch/arm/nwfpe/
# Put arch/arm/fastfpe/ to use this.
core-$(CONFIG_FPE_FASTFPE)      += $(patsubst $(srctree)/%,%,$(wildcard $(srctree)/arch/arm/fastfpe/))
core-$(CONFIG_VFP)              += arch/arm/vfp/
core-$(CONFIG_XEN)              += arch/arm/xen/
core-$(CONFIG_KVM_ARM_HOST)     += arch/arm/kvm/
core-$(CONFIG_VDSO)             += arch/arm/vdso/

# If we have a machine-specific directory, then include it in the build.
core-y                          += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
core-y                          += arch/arm/probes/
core-y                          += arch/arm/net/
core-y                          += arch/arm/crypto/
core-y                          += $(machdirs) $(platdirs)

加载顺序

section

编译器在生成.o文件时会根据所生成二进制的不同性质把它们放入相应的section中。例如函数编译后的二进制代码通常放到.text,而const关键字修饰的全局数组会放到.rodata中。GCC有除了默认的section,例如.text、.data、.bss、.debug、.dynsym等,也支持用户自定义section,在后面的内容中我们可以看到Linux大量使用GCC的扩展__attribute__ ((section(“section_name”))生成自定义section
驱动一般都会在初始化函数前面加__init;在Linux中,所有标识为__init的函数如果直接编译进入内核,成为内核镜像的一部分,在连接的时候都会放在.init.text这个区段内--#define _ _init _ _attribute_ _ ((_ _section_ _ (".init.text")))

segment

链接器在进行链接时,会根据链接脚本从输入的.o文件中挑选出感兴趣的section,把它们合并生成新的section,这些新产生的section归属于目标文件的某个segment(段),并出现在目标文件中。例如file1.o和file2.o分别有两个.text,它们在链接后生产的目标文件也会有一个.text,而这个.text既是由file1.o和file2.o的.text合并而来的

驱动加载顺序

1.makefile只能控制编译顺序,因为先编译的,所以在链接的时候分配地址的时候,就会靠前
2.链接脚本指定不同段的链接顺序;所以就产生了不同模块的加载顺序
3.initcall分配段的等级,链接到同一个段的代码,因为makefile,就会有个先后顺序了
4.也即:makefile指定单个section(built-in.a)里各符号的执行顺序,initcall指定多个section合成的segment(vmlinux)的执行顺序

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值