02 - Kbuild子系统(整理中)

1. Kbuild简介

  • Kernel build,用来编译 Linux 内核
  • 基于 GNU make 设计,对 Makefile 进行扩充
    • 菜单式配置:Kconfig
    • 预定义目标和变量:xx_defconfig、menuconfig、obj-y
    • 跨平台工具、递归式 Makefile
  • Linux 模块化设计、高度可以裁剪
    • 模块机制
    • Kbuild 子系统

2. Kbuild工作流程

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- vexpress_defconfig
make menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- uImage LOADADDR=0x60003000

2.1 编译三步骤

  • 配置阶段:编译平台、目标、配置文件
  • 编译阶段:解析 Makefile、建立目标依赖关系、按照依赖关系依次生成各个目标及目标依赖
  • 安装阶段:
    • 桌面 PC:内核镜像安装、模块安装、头文件安装
    • 嵌入式:根文件系统、Flash镜像制作等

2.2 Makefile 中的预定义

  • 预定义目标:
    • xxx_defconfig 、menuconfig 、gconfig
    • vmlinux、bzImage、zImage
    • modules、install、modules_install
    • clean、mrproper、distclean
  • 预定义变量:
    • ARCH、CROSS_COMPILE
    • obj-m、obj-y、xxx-objs

2.3 Config symbols

obj-$(CONFIG_HELLO)
config symbol<== .config
配置变量config entry <== Kconfig 文件 <== menuconfig
CONFIG_XXXconfig entry <== xxx_defconfig

3. Kbuild 编译系统构成

  • Kbuild 本质
    一个可扩展、可配置的 Makefile 框架
    递归式 Makefile、菜单式配置
  • 构成:
    • Makefile:顶层目录下的Makefile
    • .config:内核的配置文件
    • arch/$(ARCH)/Makefile:跟平台架构相关的Makefile
    • scripts/Makefile.*:通用编译规则
    • Kbuild Makefile:分布在各个子目录下
    • Kconfig:配置菜单,定义每个config symbol的属性(类型、描述、依赖等)

4. Kconfig 简介

4.1 Kconfig作用

  • 用来生成配置菜单,配置各种 config symbol,生成对应的配置变量:CONFIG_XXX
  • 每个目录下都有一个 Kconfig 文件
  • 各个 Kconfig 文件通过 source 命令构建多级菜单
  • 解析工具:scripts/kconfig/*conf

4.2 实验:内核模块添加配置菜单

在这里插入图片描述
在这里插入图片描述

4.3 Kconfig 语法

  • config:用来定义菜单选项
  • menuconfig
  • choice / endchooice
  • comment
  • if / endif
  • source:生成一个树型菜单
  • (后面几节内容讲解)

5. Kconfig 菜单条目

  • 菜单示例
config HELLOtristate "A hello module test"helpa simple kernel module test
  • 实验:
    在内核目录下新建一个test目录,用来实验 Kconfig。

在这里插入图片描述
在这里插入图片描述

6. 依赖关系:depends on

在这里插入图片描述
在这里插入图片描述

  • 内核中的依赖关系示例
config STACKPROTECTORbool "Stack Protector buffer overflow detection"depends on $(cc-option,-fstack-protector)config CC_HAS_ASM_GOTOdef_bool $(success,$(srctree)/scripts/gcc-goto.sh $(CC))config USB_DISKdepends on TEST && m

7. 反向依赖:select / imply

7.1 select

如果 TEST 被选中的话,RTC 默认也会被 “强制性”选中
在这里插入图片描述
在这里插入图片描述
具体效果可以实验下。

7.2 弱反向依赖:imply

在这里插入图片描述
在这里插入图片描述
具体效果可以实验下。

8. 内核配置中的反向依赖

示例 1:一个子系统绑定(依赖)几个驱动,当用户选择这个子系统中,这几个关联的驱动都会自动选中。
A_init()
{
if (IS_REACHABLE(CONFIG_C))
C_register(&a);

}
示例 2:

# Generic IOMAP is used to ...
config HAVE_GENERIC_IOMAPconfig GENERIC_IOMAPdepends on HAVE_GENERIC_IOMAP && FOOlib/Makefile :obj-$(CONFIG_GENERIC_IOMAP) += iomap.o# For each architecture using the generic IOMAP functionality we would see:config X86select ...select HAVE_GENERIC_IOMAPselect ...

9. Kconfig 菜单:menuconfig

在这里插入图片描述
在这里插入图片描述

等价于如下的去掉 depens on 使用if方式:
在这里插入图片描述
在这里插入图片描述

如果是如下的方式,会破坏 A 和 A0、A1 的依赖的关系,同理 B 和 B0、B1
(A 和 A0、A1 必须紧跟着,才能保持依赖关系,同理 B 和 B0、B1)
在这里插入图片描述
在这里插入图片描述

10. Kconfig 互斥选择:choice / endchoice

在这里插入图片描述
在这里插入图片描述

11. Kbuild 子菜单

  • 生成子菜单的两种方法:

11.1 方法一

  • 通过依赖关系生成菜单
  • 若菜单条目依赖前项,则其为该选项的子菜单
config Abool "A configuration"
config Bbool "B configuration"depends on A

11.2 方法二

  • 子菜单:menu / endmenu
  • 所有的菜单条目都在 menu 和 endmenu 之间的块中
  • 子菜单会继承父菜单的依赖关系
menu "test menu"
config xxx_1
…
config xxx_2
endmenu

在这里插入图片描述
在这里插入图片描述

12. 更多编译目标

make config
make nconfig:基于文本的菜单配置
make menuconfig:依赖 ncurses 图形库
# apt-get install libncurses5-dev
make xconfig:基于窗口的配置菜单,依赖Qt库
# add-apt-repository ppa:rock-core/qt4
# apt-get install libqt4-dev
make gconfig:基于GTK的菜单配置
# apt-get install gtk+-2.0 glib-2.0 libglade2-dev

.config:

在这里插入图片描述

make clean
make mrproper
make distclean

13. 文件 .config

13.1 简介

  • .config 文件是如何生成的?
  • .config 文件里都是什么?
  • .config 文件有什么用?如何参与编译工作?
  • 参考:scripts/kconfig/mconf.c、conf.c

在这里插入图片描述
在这里插入图片描述

13.2 .config 的生成

13.2.1 .config 生成的第一阶段

  1. make vexpress_defconfig ==> .config
  2. make menuconfig ==> .config

在这里插入图片描述

13.2.2 .config 生成的第二阶段

  • .config ==> syncconfig ==> Makefile
include/config/auto.conf:用来配置Makefile
include/generated/autoconf.h:供C程序引用
include/config/*.h:空头文件,用于构建依赖关系
# Makefile:
KCONFIG_CONFIG ?= .config
cmd_syncconfig = $(MAKE) -f $(srctree)/Makefile syncconfig
PHONY += include/config/auto.conf
%/config/auto.conf  %/generated/autoconf.h :  $(KCONFIG_CONFIG)+$(call cmd,syncconfig)# include/config/auto.conf:
deps_config := kernel/trace/Kconfig certs/Kconfig fs/udf/Kconfig … include/config/auto.conf: \$(deps_config)# scripts/Kbuild.include:
cmd = @set -e; $(echo-cmd) $(cmd_$(1))

13.3 .config 如何参与编程

  • .config ==> syncconfig ==> include/config/auto.conf
  • .config ==> syncconfig ==> include/config/tristate.conf

在 Makefile 中引用 auto.conf 定义的配置变量(config symbols)。示例:

# 顶层 Makefile:
need-config := 1
ifdef need-config
include include/config/auto.conf
endif# include include/config/auto.conf:
CONFIG_USB=y# drivers/usb/Makefile:
obj-$(CONFIG_USB) += core/

13.4 .config 如何被 C 语言引用

  • .config ==> syncconfig ==> include/generated/autoconf.h
  • 配置变量(config symbols) –> C 语言的宏定义

在 C 程序中引用 autoconf.h 定义的宏:

// include/generated/autoconf.h:
#define CONFIG_USB_MON 1
// include/linux/usb.h:
#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
struct mon_bus *mon_bus; /* non-null when associated */
int monitored; /* non-zero when monitored */
#endif
gcc –Iinclude include/generated/autoconf.h –c hello.c

14. Kbuild Makefile 工作流程

14.1 Linux内核镜像的流程

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- vexpress_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- uImage LOADADDR=ox60003000

14.2 Kbuild Makefile 的构成

  • 顶层Makefile:主要用来调用相应规则的Makefile
  • .config:用户配置的各种选项
  • arch/$(ARCH)/Makefile:跟平台相关的Makefile
  • 各个目录下的Makefile:负责编译各个模块
  • scripts/Makefile.* :定义各种通用规则

14.3 scripts/Makefile.* :各类规则文件

scripts/Makefile.build:通用规则,用来编译built-in.a、lib.a
scripts/Makefile.lib:负责分析obj-y、obj-y和子目录中的subdir-y等
scripts/Makefile.include:一些通用定义,被Makefile.* 包含使用
scripts/Makefile.host:编译各种主机工具
scripts/Makefile.headerinst:头文件安装规则
scripts/Makefile.modinst:模块installguize
scripts/Makefile.modpost:模块编译,由.o和.mod生成module.ko
scripts/Makefile.modsign:模块签名
scripts/Makefile.clean:clean规则,make clean时调用

14.4 Kbuild Makefile 预定义目标和变量

  • obj-m:将当前文件编译为独立的模块
  • obj-y:将当前文件编译进内核
  • xxx-objs:一个模块依赖的多个源文件
  • bzImage:
  • menuconfig:
  • CONFIG_xxx:
    • include include/config/auto.conf
    • include/config/auto.conf.cmd

14.5 Kbuild Makefile 工作流程

  1. 根据 ARCH 变量,首先 include arch/$(ARCH)/Makefile
  2. 读取 .config 文件:读取用户的各种配置变量
  3. 解析预定义目标、目标,构建依赖关系
  4. 编译各个模块或组件(使用 scripts/Makefile.*)
    • 将每个目录下的源文件编译为对应的 .o 目标文件
    • 将 .o 目标文件归档为 built-in.a
  5. 将所有对象链接成 vmlinux
  6. 编译模块…

15. vmlinux 编译过程分析

15.1 内核镜像编译流程

在这里插入图片描述

15.2 默认目标的依赖:vmlinux

# Top Makefile:
# That's our default target when none is given on the command line
PHONY := __all
__all: all
all: vmlinux
vmlinux: scripts/link-vmlinux.sh autoksyms_recursive $(vmlinux-deps)+$(call if_changed,link-vmlinux)
vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_OBJS) $(KBUILD_VMLINUX_LIBS)export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds
KBUILD_VMLINUX_OBJS := $(head-y) $(patsubst %/,%/built-in.a, $(core-y))
KBUILD_VMLINUX_OBJS += $(addsuffix built-in.a, $(filter %/, $(libs-y)))
KBUILD_VMLINUX_OBJS += $(patsubst %/,%/built-in.a, $(drivers-y))

15.2.1 KBUILD_VMLINUX_OBJS 变量

# arch/arm/kernel/Makefile:
head-y := arch/arm/kernel/head$(MMUEXT).o
core-y += arch/arm/
core-y += $(machdirs) $(platdirs)
libs-y := arch/arm/lib/ $(libs-y)# Makefile:
core-y := init/ usr/
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
libs-y := lib/
drivers-y := drivers/ sound/
drivers-y += net/ virt/

展开后:

KBUILD_VMLINUX_OBJS := arch/arm/kernel/head.o arch/arm/built-in.a init/built-in.a usr/built-in.a kernel/built-in.a certs/built-in.a mm/ built-in.a fs/ built-in.a ipc/ built-in.a security/built-in.a crypto/built-in.a block/built-in.a lib/built-in.a arch/arm/lib/built-in.a drivers/built-in.a sound/built-in.a net/built-in.a virt/ built-in.a

15.2.2 KBUILD_VMLINUX_LIBS 变量

KBUILD_VMLINUX_LIBS := $(patsubst %/, %/lib.a, $(libs-y))
libs-y := lib/
libs-y := arch/arm/lib/ $(libs-y)

展开后:

KBUILD_VMLINUX_LIBS := lib/lib.a arch/arm/lib/lib.a

15.2.3 autoksyms_recursive

autoksyms_recursive: descend modules.order$(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh \"$(MAKE) -f $(srctree)/Makefile vmlinux"

15.3 生成 vmlinux 的规则

# Makefile:
vmlinux: scripts/link-vmlinux.sh autoksyms_recursive $(vmlinux-deps)+$(call if_changed,link-vmlinux)# scripts/Kbuild.include:
if_changed = $(if $(newer-prereqs)$(cmd-check), \$(cmd); \printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:)
cmd = @set -e; $(echo-cmd) $(cmd_$(1))
# Makefile:
cmd_link-vmlinux = \$(CONFIG_SHELL) $< "$(LD)" "$(KBUILD_LDFLAGS)" "$(LDFLAGS_vmlinux)";$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)
# SHELL used by kbuild
CONFIG_SHELL := sh
LDFLAGS_vmlinux = --build-id=sha1 --orphan-handling=warn

展开后:

cmd_link-vmlinux = sh scripts/link-vmlinux.sh "ld.lld""--build-id=sha1 --orphan-handling=warn";true
  • scripts/link-vmlinux.sh 脚本
    • 链接 $(KBUILD_VMLINUX_OBJS) 中的所有 built-in.a
    • 链接 $(KBUILD_VMLINUX_LIBS)
    • 符号处理:生成 system.map、include/generated/autoksyms.h 等文件
modpost_link()
{local objectsobjects="--whole-archive \${KBUILD_VMLINUX_OBJS} \--no-whole-archive \--start-group \${KBUILD_VMLINUX_LIBS} \--end-group"${LD} ${KBUILD_LDFLAGS} -r -o ${1} ${objects}
}

16. built-in.a 生成分析

默认目标的依赖分析:

Makefile:

vmlinux-dirs := ( p a t s u b s t (patsubst %/,%, (patsubst(filter %/,
$(core-y) $(core-m) $(drivers-y) $(drivers-m)
$(libs-y) $(libs-m)))
build-dirs:= $(vmlinux-dirs)

展开后:
build-dirs:= init lib drivers net sound certs crypto ipc kernel mm …

PHONY += descend $(build-dirs)
$(build-dirs): prepare
( Q ) (Q) (Q)(MAKE) ( b u i l d ) = (build)= (build)=@
single-build=$(if $(filter-out $@/, $(filter $@/%, $(KBUILD_SINGLE_TARGETS))),1)
need-builtin=1 need-modorder=1

KBUILD_SINGLE_TARGETS := $(addprefix $(extmod-prefix), $(single-no-ko))
extmod-prefix = $(if ( K B U I L D E X T M O D ) , (KBUILD_EXTMOD), (KBUILDEXTMOD),(KBUILD_EXTMOD)/)
single-no-ko := $(sort $(patsubst %.ko, %.mod, $(MAKECMDGOALS)))

Kbuild.include:

build := -f $(srctree)/scripts/Makefile.build obj

●示例:编译sound目录

__build展开后:
__build: sound/built-in.a

●sound/built-in.a:
– 单文件模块:obj-y=hello.o
– 复合模块:
obj-y=hello.o hello-y= a.o b.o c.o
obj-y=hello.o hello-objs= a.o b.o c.o
– 子目录:obj-y=subdir

scripts/Makefile.build:

$(obj)/built-in.a: $(real-obj-y) FORCE
$(call if_changed,ar_builtin)

cmd_ar_builtin = rm -f $@; $(AR) cDPrST $@ $(real-prereqs)
real-prereqs = $(filter-out $(PHONY), $^)

real-obj-y := $(foreach m, $(obj-y), $(if $(strip ( ( ((m:.o=-objs)) ( ( ((m:.o=-y)) ( ( ((m:.o=-))), ( ( ((m:.o=-objs)) ( ( ((m:.o=-y)),$(m)))
real-obj-y := $(addprefix ( o b j ) / , (obj)/, (obj)/,(real-obj-y))

17.单个目标文件生成分析

scripts/Makefile.build:

$(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_dep) FORCE
$(call if_changed_rule,cc_o_c)
$(call cmd,force_checksrc)

define rule_cc_o_c
$(call cmd_and_fixdep,cc_o_c)
$(call cmd,gen_ksymdeps)
$(call cmd,checksrc)
$(call cmd,checkdoc)
$(call cmd,objtool)
$(call cmd,modversions_c)
$(call cmd,record_mcount)
endef

scripts/Kbuild.include:

if_changed_rule = $(if ( n e w e r − p r e r e q s ) (newer-prereqs) (newerprereqs)(cmd-check),KaTeX parse error: Expected group after '_' at position 6: (rule_̲(1)),@😃
cmd = @set -e; $(echo-cmd) KaTeX parse error: Expected group after '_' at position 5: (cmd_̲(1))
cmd_and_fixdep =
$(cmd);
scripts/basic/fixdep $(depfile) @ ′ @ ' @(make-cmd)’ > $(dot-target).cmd;
rm -f $(depfile)

quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<

cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $<

Makefile:

CHECK = sparse
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__
-Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF)

命令展开后:
%.o : %.c
gcc –c –o $@ %.c
sparse -D__linux__ -Dlinux -D__STDC__ …

●总结:
.c ==> .o ==> 递归生成built-in.a ==> vmlinux
18.zImage生成分析
18.1 内核镜像生成过程

CC sound/xx.o
CC xxxx/xxx.o

LD vmlinux
SORTTAB vmlinux
SYSMAP System.map
OBJCOPY arch/arm/boot/Image
Kernel: arch/arm/boot/Image is ready
GZIP arch/arm/boot/compressed/piggy_data
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
UIMAGE arch/arm/boot/uImage

18.2 Image镜像生成分析

arch/arm/Makefile:

KBUILD_IMAGE := $(boot)/zImage
all: $(notdir $(KBUILD_IMAGE))
zImage: Image
BOOT_TARGETS = zImage Image uImage
$(BOOT_TARGETS): vmlinux
( Q ) (Q) (Q)(MAKE) ( b u i l d ) = (build)= (build)=(boot) MACHINE=$(MACHINE) ( b o o t ) / (boot)/ (boot)/@
@$(kecho) ’ Kernel: ( b o o t ) / (boot)/ (boot)/@ is ready’

其中:
build := -f ( s r c t r e e ) / s c r i p t s / M a k e f i l e . b u i l d o b j b o o t : = a r c h / a r m / b o o t m a c h i n e − y 为 空 , M A C H I N E : = a r c h / a r m / m a c h − (srctree)/scripts/Makefile.build obj boot := arch/arm/boot machine-y为空,MACHINE := arch/arm/mach- (srctree)/scripts/Makefile.buildobjboot:=arch/arm/bootmachineyMACHINE:=arch/arm/mach(word 1,$(machine-y))/
所以 MACHINE :=
boot := arch/arm/boot
zImage: vmlinux
make -f scripts/Makefile.build obj=arch/arm/boot arch/arm/boot/zImage
Image: vmlinux
make -f scripts/Makefile.build obj=arch/arm/boot arch/arm/boot/Image

arch/arm/Makefile:

$(obj)/Image: vmlinux FORCE
$(call if_changed,objcopy)
$(obj)/compressed/vmlinux: $(obj)/Image FORCE
( Q ) (Q) (Q)(MAKE) ( b u i l d ) = (build)= (build)=(obj)/compressed $@
$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
$(call if_changed,objcopy)

展开后:
arch/arm/boot/Image: vmlinux
arm-linux-gnueabi-objcopy -O binary -R .comment -S vmlinux Image
arch/arm/boot/compressed/vmlinux:arch/arm/boot/Image
make -f scripts/Makefile.build obj=arch/arm/boot/compressed vmlinux
arch/arm/boot/zImage: arch/arm/boot/compressed/vmlinux
arm-linux-gnueabi-objcopy -O binary -R .comment -S vmlinux zImage

●分析一下其中的Image的生成:
arch/arm/boot/Image: vmlinux
arm-linux-gnueabi-objcopy -O binary -R .comment -S vmlinux Image

参数说明:
-O:生成一个二进制文件
-R:从一个目标文件中删除指定的section
-S:–strip-all,全方位压缩vmlinux文件
18.3 piggy.o生成分析
$(obj)/piggy.o: $(obj)/piggy_data
$(obj)/piggy_data: $(obj)/…/Image FORCE
( c a l l i f c h a n g e d , (call if_changed, (callifchanged,(compress-y))

.config:

compress-$(CONFIG_KERNEL_GZIP) = gzip

Makefile.lib:

cmd_gzip = cat $(real-prereqs) | $(KGZIP) -n -f -9 > $@
KGZIP = gzip

18.4 arch/arm/boot/compressed/vmlinux生成分析
arch/arm/boot/compressed/vmlinux: arch/arm/boot/Image
make -f scripts/Makefile.build obj=arch/arm/boot/compressed vmlinux

arch/arm/boot/compressed/Makefile:

$(obj)/vmlinux: $(obj)/vmlinux.lds ( o b j ) / (obj)/ (obj)/(HEAD) $(obj)/piggy.o
$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3)
$(bswapsdi2) $(efi-obj-y) FORCE
( c a l l i f c h a n g e d , l d ) @ (call if_changed,ld) @ (callifchanged,ld)@(check_for_bad_syms)

其中:
HEAD = head.o
OBJS += misc.o decompress.o
cmd_ld = $(LD) $(ld_flags) $(real-prereqs) -o $@
LD = $(CROSS_COMPILE)ld
ld_flags = $(KBUILD_LDFLAGS) $(ldflags-y) KaTeX parse error: Expected group after '_' at position 9: (LDFLAGS_̲(@F))
ldflags-y += $(EXTRA_LDFLAGS),其中EXTRA_LDFLAGS为空
real-prereqs = $(filter-out $(PHONY), $^)
展开后:
arch/arm/boot/compressed/vmlinux: vmlinux.lds head.o misc.o decompress.o piggy.o
arm-linux-gnueabi-ld -EL vmlinux.lds compressed/head.o compressed/piggy.o

18.5 zImage镜像生成分析
arch/arm/boot/zImage: arch/arm/boot/compressed/vmlinux
arm-linux-gnueabi-objcopy -O binary -R .comment -S vmlinux zImage

参数说明:
-O:生成一个二进制文件
-R:从一个目标文件中删除指定的section
-S:–strip-all,全方位压缩vmlinux文件
19.uImage镜像生成分析
19.1 uImage镜像生成分析
mkimage –A arm -O linux –T kernel –C none –a 0x60003000 –e 0x60003000 -d zImage uImage

mkimage参数说明:
-A:指定CPU架构类型
-O:指定操作系统类型
-T:指定image类型
-C:采用的压缩方式:none、gzip、bzip2等
-a:内核加载地址
-e:内核镜像入口地址
19.2 uImage启动过程
-a ==> set load address to ‘addr’ (hex) —— 镜像的加载地址
-e ==> set entry point to ‘ep’ (hex) —— 镜像的运行地址
首先要知道mkimage做出来的文件,会有64字节的描述信息在文件头部。而Uboot会将镜像文件加载到 -a指定的地址,并跳到 -e地址运行。
这里有几种情况:
1、uImage下载到内存的地址,和 -a指定的地址相同,uboot不会对镜像做内存搬移。
2、uImage下载到内存的地址,和-a指定的地址不同,uboot会将下载地址的uImage镜像文件(去掉64字节头部信息)搬移到-a指定的地址。
3、-a和 -e参数地址相同时,理论上,需要uImage的下载地址和 -a地址不同,镜像做过搬移后,到 -e地址运行是正常的。
4、-a和 -e参数地址不同,固定为 -a + 0x40= -e,镜像不会搬移(头部64字节信息不会去掉),到 -e地址运行才会正常。
20.内核模块编译分析
20.1 内核模块编译信息
CC [M] drivers/char/hello.o
MODPOST Module.symvers
CC [M] drivers/char/hello.mod.o
LD [M] drivers/char/hello.ko

20.2 内核模块编译步骤
1.步骤一:
将每个源文件编译为对应的 .o 目标文件
将单个或多个 .o 目标文件链接成模块文件module.o
生成对应的module.mod文件
生成modules.order文件,里面保存所有的ko文件信息
●流程示例:
add.o / sub.o / … ==> hello.o ==> hello.mod ==> modules.order
或者hello.o ==> hello.mod ==> modules.order
2.步骤二:
从modules.order文件中查找所有的ko文件
使用modpost,为每个ko模块创建module.mod.c文件
创建Module.symvers文件,保存导出的符号(EXPORT_SYMBOL)及CRC值
将module.o和module.mod.o链接成module.ko
●流程示例:
modules.order ==> hello.mod.c ==> Module.symvers
hello.o + hello.mod.o ==> hello.ko
3.步骤三:
生成和内核模块相关的信息:版本魔幻数
License、versions、alias
20.3 此前实验代码示例

20.4 模块编译对应的Makefile
●modules目标对应的规则:

Makefile:

modules: $(if $(KBUILD_BUILTIN),vmlinux) modules_check modules_prepare
( Q ) (Q) (Q)(MAKE) -f $(srctree)/scripts/Makefile.modpost

scripts/Makefile.modpost:

PHONY := __modpost

__modpost: $(output-symdump)
( Q ) (Q) (Q)(MAKE) -f $(srctree)/scripts/Makefile.modfinal

scripts/Makefile.modfinal:

PHONY := __modfinal

__modfinal: $(modules)

find all .ko modules listed in modules.order

modules := $(sort $(shell cat $(MODORDER)))

cat modules.order

drivers/char/hello.ko

scripts/Makefile.modfinal:

( m o d u l e s ) : + (modules): %.ko : %.o %.mod.o scripts/module.lds FORCE + (modules):+(call if_changed,ld_ko_o)
cmd_ld_ko_o =
$(LD) -r $(KBUILD_LDFLAGS) $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE)
-T scripts/module.lds -o $@ $(filter %.o, $^);
$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)

21.modules_install过程分析
模块安装信息:

●模块安装对应的Makefile

Makefile:

modules_install: emodinst _emodinst_post
emodinst:
$(Q)mkdir -p ( M O D L I B ) / (MODLIB)/ (MODLIB)/(install-dir)
( Q ) (Q) (Q)(MAKE) -f $(srctree)/scripts/Makefile.modinst
_emodinst_post: emodinst
$(call cmd,depmod)

scripts/Makefile.modinst:

PHONY := __modinst
__modinst: $(modules)
modules := $(sort $(shell cat $(if ( K B U I L D E X T M O D ) , (KBUILD_EXTMOD), (KBUILDEXTMOD),(KBUILD_EXTMOD)/)modules.order))
$(modules):
( c a l l c m d , m o d u l e s i n s t a l l , (call cmd,modules_install, (callcmd,modulesinstall,(MODLIB)/$(modinst_dir))

modinst_dir = $(if ( K B U I L D E X T M O D ) , (KBUILD_EXTMOD), (KBUILDEXTMOD),(ext-mod-dir),kernel/$(@D))

cmd_modules_install =
mkdir -p $(2) ;
cp $@ $(2) ;
$(mod_strip_cmd) ( 2 ) / (2)/ (2)/(notdir $@) ;
$(mod_sign_cmd) ( 2 ) / (2)/ (2)/(notdir $@) ( p a t s u b s t (patsubst %,|| true, (patsubst(KBUILD_EXTMOD)) ;
$(mod_compress_cmd) ( 2 ) / (2)/ (2)/(notdir $@)

22.headers_install过程分析
●目标header对应的规则

Makefile:

headers: $(version_h) scripts_unifdef uapi-asm-generic archheaders archscripts
$(if $(wildcard ( s r c t r e e ) / a r c h / (srctree)/arch/ (srctree)/arch/(SRCARCH)/include/uapi/asm/Kbuild),
$(error Headers not exportable for the $(SRCARCH) architecture))
( Q ) (Q) (Q)(MAKE) $(hdr-inst)=include/uapi
( Q ) (Q) (Q)(MAKE) ( h d r − i n s t ) = a r c h / (hdr-inst)=arch/ (hdrinst)=arch/(SRCARCH)/include/uapi

其中:
hdr-inst := -f $(srctree)/scripts/Makefile.headersinst obj
简化一下
headers: $(version_h) scripts_unifdef uapi-asm-generic archheaders archscripts
make -f scripts/Makefile.headersinst obj=include/uapi
make -f scripts/Makefile.headersinst obj=arch/arm/include/uapi

scripts/Makefile.headersinst:

PHONY := __headers
__headers: $(all-headers)
$(call cmd,remove)
all-headers := $(src-headers) $(gen-headers)
src-headers := $(if $(src-subdirs), $(shell cd $(src) && find $(src-subdirs) -name ‘*.h’))

其中:
src = include/uapi
src-headers = include/uapi/$(src-subdirs)/.h
src-headers := $(filter-out $(no-export-headers), $(src-headers))
src-headers := include/uapi/asm-generic/
.h include/uapi/linux/.hinclude/uapi/sound/.h …

●src-headers对应的规则:
$(src-headers): $(dst)/%.h: $(src)/%.h $(srctree)/scripts/headers_install.sh FORCE
$(call if_changed,install)

其中:
src = include/uapi
dst := usr/include
cmd_install = $(CONFIG_SHELL) $(srctree)/scripts/headers_install.sh $< $@
● gen-headers对应的规则:

scripts/Makefile.headersinst:

gen := ( o b j t r e e ) / (objtree)/ (objtree)/(subst include/,include/generated/,$(obj))
gen-headers := $(if $(gen-subdirs), $(shell cd $(gen) && find $(gen-subdirs) -name ‘*.h’))
$(gen-headers): $(dst)/%.h: $(gen)/%.h $(srctree)/scripts/headers_install.sh FORCE
$(call if_changed,install)

其中:
gen = include/generated/uapi
dst := usr/include
cmd_install = $(CONFIG_SHELL) $(srctree)/scripts/headers_install.sh $< $@
23.内核中的空头文件探秘
●前面内容:
.config生成的三个主要文件:
– include/config/auto.conf:用来配置Makefile
– include/generated/autoconf.h:在C程序中引用
– include/config/.h:
●Kbuild Makefile
跟踪三种依赖关系:(修改下面的任意一项,编译都能够跟踪到修改的依赖项)
– 编译所需要的所有源文件:
.c
– 源文件*.c中包含的各种头文件:*.h
– 所有程序中使用的配置选项:CONFIG_XX(内核会生成对应的空头文件)
#include <xx.h>
#ifdef CONFIG_SMP
__boot_cpu_id = cpu;
#endif

23.1 示例:头文件依赖
23.1.1 方式一

没有添加对 pi.h 文件的依赖,修改PI从3.14到3.1415926时,a.out没有对pi.h产生依赖关系,所以:

在Makefile中添加对pi.h的依赖:

23.1.2 方式二
●gcc的-MD编译选项
生成文件关联的信息,输出的信息导入到hello_pi.d的文件里面。

●在Makefile中包含hello_pi.d文件

23.2 内核中头文件依赖

23.2.1 内核文件编译示例

scripts/Makefile.lib:
c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)
-include $(srctree)/include/linux/compiler_types.h
$(__c_flags) $(modkern_cflags)
$(basename_flags) $(modname_flags)

.header_wuxiang.o.cmd:

source_drivers/char/header_wuxiang.o := drivers/char/header_wuxiang.c

deps_drivers/char/header_wuxiang.o :=
$(wildcard include/config/smp.h)
$(wildcard include/config/wuxiang.h)
include/linux/kconfig.h
$(wildcard include/config/cc/version/text.h)

drivers/char/pi.h \

drivers/char/header_wuxiang.o: $(deps_drivers/char/header_wuxiang.o)

$(deps_drivers/char/header_wuxiang.o):

Makefile.build:

$(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_dep) FORCE
$(call if_changed_rule,cc_o_c)
-include ( f o r e a c h f , (foreach f, (foreachf,(existing-targets),$(dir ( f ) ) . (f)). (f)).(notdir $(f)).cmd)

existing-targets := $(wildcard $(sort $(targets)))
targets += $(targets-for-builtin) $(targets-for-modules)

Kbuild.include:

Execute the command and also postprocess generated .d dependencies file.

if_changed_dep = $(if ( n e w e r − p r e r e q s ) (newer-prereqs) (newerprereqs)(cmd-check),$(cmd_and_fixdep),@😃
cmd_and_fixdep =
$(cmd);
scripts/basic/fixdep $(depfile) @ ′ @ ' @(make-cmd)’ > $(dot-target).cmd;
rm -f $(depfile)

depfile = $(subst ( c o m m a ) , , (comma),_, (comma),,(dot-target).d) # depfile保存gcc -MD生成的依赖文件

Name of target with a ‘.’ as filename prefix. foo/bar.o => foo/.bar.o

dot-target = $(dir @ ) . @). @).(notdir $@)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/237445.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java开发面试:常见业务场景之单点登录SSO(JWT)、权限认证、上传数据的安全性的控制、项目中遇到的问题、日志采集(ELK)、快速定位系统的瓶颈

单点登录&#xff08;SSO&#xff09; 单点登录&#xff0c;Single Sign On&#xff08;简称SSO&#xff09;,只需要登录一次&#xff0c;就可以访问所有信任的应用系统。 如果是单个tomcat服务&#xff0c;session可以共享&#xff0c;如果是多个tomcat&#xff0c;那么服务s…

tcp 的限制 (TCP_WRAPPERS)

#江南的江 #每日鸡汤&#xff1a;青春是打开了就合不上的书&#xff0c;人生是踏上了就回不了头的路&#xff0c;爱情是扔出了就收不回的赌注。 #初心和目标&#xff1a;拿到高级网络工程师 TCP_WRAPPERs Tcp_wrappers 对于七层模型中是位于第四层的安全工具&#xff0c;他…

微信小程序 动态设置状态栏样式

onLoad(options) {//修改状态栏标题wx.setNavigationBarTitle({title: 页面标题, //页面标题success: () > {}, //接口调用成功的回调函数fail: () > {}, //接口调用失败的回调函数complete: () > {} //接口调用结束的回调函数&#xff08;调用成功、失败…

[CVPR 2023:3D Gaussian Splatting:实时的神经场渲染]

文章目录 前言小结 原文地址&#xff1a;https://blog.csdn.net/qq_45752541/article/details/132854115 前言 mesh 和点是最常见的3D场景表示&#xff0c;因为它们是显式的&#xff0c;非常适合于快速的基于GPU/CUDA的栅格化。相比之下&#xff0c;最近的神经辐射场&#xf…

从0开始学Git指令

从0开始学Git指令 因为网上的git文章优劣难评&#xff0c;大部分没有实操展示&#xff0c;所以打算自己从头整理一份完整的git实战教程&#xff0c;希望对大家能够起到帮助&#xff01; 初始化一个Git仓库&#xff0c;使用git init命令。 添加文件到Git仓库&#xff0c;分两步…

智能优化算法应用:基于金鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于金鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于金鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.金鹰算法4.实验参数设定5.算法结果6.参考文献7.MA…

数据库学习日常案例20231221-oracle libray cache lock分析

1 问题概述&#xff1a; 阻塞的源头为两个ddl操作导致大量的libray cache lock 其中1133为gis sde的create table as语句。 其中697为alter index语句。

案例125:基于微信小程序的个人健康数据管理系统的设计与实现

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

龙蜥开源操作系统能解决CentOS 停服造成的空缺吗?

龙蜥开源操作系统能解决CentOS 停服造成的空缺吗&#xff1f; 本文图片来源于龙蜥&#xff0c;仅做介绍时引用用途&#xff0c;版权归属龙蜥和相关设计人员。 一、《国产服务器操作系统发展报告&#xff08;2023&#xff09;》称操作系统已步入 2.0 时代&#xff0c;服务器操作…

MacOS+Homebrew+iTerm2+oh my zsh+powerlevel10k美化教程

MacOS终端 你是否已厌倦了MacOS终端的大黑屏&#xff1f; 你是否对这种美观的终端抱有兴趣&#xff1f; 那么&#xff0c;接下来我将会教你用最简单的方式来搭建一套自己的终端。 Homebrew的安装 官网地址&#xff1a;Homebrew — The Missing Package Manager for macOS (o…

Hbase的安装配置

注&#xff1a;本文默认已经完成hadoop的下载以及环境配置 1.上传zookeeper和hbase压缩包到指令路径并且解压 (理论上讲&#xff0c;hbase其实内置了zookeeper&#xff0c;我们也可以不另外下载&#xff0c;另外下载的目的在于减少组件间依赖性) cd /home mkir hbase cd /hom…

泽攸科技SEM台式扫描电子显微镜

泽攸科技是一家国产的科学仪器公司&#xff0c;专注于研发、生产和销售原位电镜解决方案、扫描电镜整机、台阶仪、探针台等仪器。目前台式扫描电镜分为三个系列&#xff1a;ZEM15、ZEM18、ZEM20。 ZEM15台式扫描电镜&#xff1a; ZEM18台式扫描电镜&#xff1a; ZEM20台式扫描…

WeakMap 和 WeakSet:解决内存泄漏避免循环引用(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Debian在升级过程中报错

当我们在升级的过程中出现如下报错信息 报错信息如下所示&#xff1a; The following signatures couldnt be verified because the public key is not available: NO_PUBKEY ED444FF07D8D0BF6 W: GPG error: http://mirrors.jevincanders.net/kali kali-rolling InRelease: …

版本化数据库管理工具Flyway介绍和Spring Boot集成使用

文章目录 核心功能如何使用 Flyway最佳实践Spring Boot使用 Flyway 是一个版本化数据库管理工具&#xff0c;用于跟踪、管理和应用数据库的变化。它非常适合在团队开发环境中使用&#xff0c;其中多个人员可能会在数据库结构进行更改。Flyway 通过版本控制可以帮助你确保所有人…

用户管理第2节课-idea 2023.2 后端一删除表,从零开始---【本人】

一、清空model文件夹下&#xff0c;所有文件 1.1.1效果如下&#xff1a; 1.1代码内容 package com.daisy.usercenter.model;import lombok.Data;Data public class User {private Long id;private String name;private Integer age;private String email; }二、清空mapper文件…

Ajax Search Pro Live WordPress网站内容实时搜索插件

点击阅读Ajax Search Pro Live WordPress网站内容实时搜索插件原文 Ajax Search Pro Live WordPress网站内容实时搜索插件是 WordPress 最好的实时搜索引擎插件。高度可定制&#xff0c;具有许多功能和选项&#xff0c;可提供最佳结果&#xff01;用更美观、更高效的搜索引擎替…

STM32 使用ARM仿真器设置

STM32单片机程序下载到单片机芯片中有两种方式&#xff0c;①编译生成HEX&#xff0c;使用程序烧录软件刷到单片机芯片里。②使用ARM仿真器下载程序。使用ARM仿真器的优势是&#xff0c;在工程编译没问题直接在Keil软件里就可以将程序下载到单片机里&#xff0c;并且程序可以在…

代码随想录刷题题Day19

刷题的第十九天&#xff0c;希望自己能够不断坚持下去&#xff0c;迎来蜕变。&#x1f600;&#x1f600;&#x1f600; 刷题语言&#xff1a;C Day19 任务 ● 669. 修剪二叉搜索树 ● 108.将有序数组转换为二叉搜索树 ● 538.把二叉搜索树转换为累加树 1 修剪二叉搜索树 669…

华为全屋wifi6蜂鸟套装标准

华为政企42 华为政企 目录 上一篇华为安防监控摄像头下一篇华为企业级无线路由器