linux kernel
systemd
qemu
课程报名
linux内核构建流程
课程介绍
相关文章
相关视频
问答
进入linux内核源码目录
生成内核配置
make defconfig // 生成内核的默认配置
Makefile:%config
scripts/kconfig/Makefile:defconfig
scripts/kconfig/conf --defconfig=arch/x86/configs/x86_64_defconfig Kconfig
scripts/kconfig/conf.c:main // conf程序的main函数
scripts/kconfig/parser.y:conf_parse // 解析Kconfig中定义的内核配置项
scripts/kconfig/confdata.c:conf_read // 根据arch/x86/configs/x86_64_defconfig文件的内容,为对应的内核配置项赋值
scripts/kconfig/conf.c:conf_set_all_new_symbols // 对于那些还没有值的内核配置项,如果Kconfig中为其定义了默认值,则把它设置为默认值,否则设置为其类型的零值
scripts/kconfig/confdata.c:conf_write // 将最终的内核配置写到.config文件里
scripts/kconfig/confdata.c:conf_write_autoconf // 为 Makefile/c/rust 生成对应的 include/config/auto.conf, include/generated/autoconf.h, include/generated/rustc_cfg 文件
linux内核各种配置方式的区别
构建内核
make -j4 // 参数-j4表示最大允许4个任务同时运行,根据机器配置调节该参数值,当然,也可以不加这个参数
Makefile:__all // 当make没有指定构建目标时,就会执行Makefile里的第一个目标,对于linux内核来说,就是__all
Makefile:__all // 子节点表示当前节点的依赖项,或者是要执行的命令
Makefile:all
Makefile:vmlinux
Makefile:vmlinux.o
Makefile:vmlinux_o
Makefile:vmlinux.a
Makefile:./built-in.a lib/lib.a arch/x86/lib/lib.a
Makefile:.
Makefile:prepare
Makefile:prepare0
Makefile:archprepare
arch/x86/Makefile:archheaders
make -f ./scripts/Makefile.build obj=arch/x86/entry/syscalls all // 生成和系统调用相关的头文件,比如 arch/x86/include/generated/asm/syscalls_64.h 和 arch/x86/include/generated/uapi/asm/unistd_64.h
arch/x86/Makefile:archscripts
make -f ./scripts/Makefile.build obj=arch/x86/tools relocs // 构建 arch/x86/tools/relocs 工具
Makefile:scripts
make -f ./scripts/Makefile.build obj=scripts // 构建其他各种工具
Makefile:asm-generic
Makefile:uapi-asm-generic
make -f ./scripts/Makefile.asm-headers obj=arch/x86/include/generated/uapi/asm generic=include/uapi/asm-generic // 以 include/uapi/asm-generic 目录中的头文件为模板,生成平台通用的头文件,写到 arch/x86/include/generated/uapi/asm 目录里
make -f ./scripts/Makefile.asm-headers obj=arch/x86/include/generated/asm generic=include/asm-generic // 以 include/asm-generic 目录中的头文件为模板,生成平台通用的头文件,写到 arch/x86/include/generated/asm 目录里
make -f ./scripts/Makefile.build obj=scripts/mod // 构建 modpost 工具,这个后面会用到
make -f ./scripts/Makefile.build obj=. prepare // 生成一些头文件,比如 include/generated/asm-offsets.h
make -f ./scripts/Makefile.build obj=rust // 编译rust目录里的代码
Makefile:prepare
Makefile:tools/objtool // 构建objtool工具,该工具在内核编译过程中,有着非常重要作用
make -f ./scripts/Makefile.build obj=. need-builtin=1 need-modorder=1 // 递归构建所有目录,并在每一级目录生成 built-in.a 和 modules.order,父目录的 built-in.a 和 modules.order 包含子目录的 built-in.a 和 modules.order,另外,lib 和 arch/x86/lib 目录里还会生成 lib.a
scripts/Makefile.build:./
scripts/Makefile.build:./built-in.a // 在根目录生成 built-in.a
scripts/Makefile.build:kernel/built-in.a
scripts/Makefile.build:kernel
make -f ./scripts/Makefile.build obj=kernel need-builtin=1 need-modorder=1 // 该命令会生成 kernel/built-in.a 和 kernel/modules.order
scripts/Makefile.build:kernel/
scripts/Makefile.build:kernel/built-in.a
scripts/Makefile.build:kernel/fork.o // 由 fork.c 生成
scripts/Makefile.build:kernel/sched/built-in.a
scripts/Makefile.build:kernel/sched
make -f ./scripts/Makefile.build obj=kernel/sched need-builtin=1 need-modorder=1 // 该命令会生成 kernel/sched/built-in.a 和 kernel/sched/modules.order
scripts/Makefile.build:kernel/sched/
scripts/Makefile.build:kernel/sched/built-in.a
scripts/Makefile.build:kernel/sched/core.o // 由 core.c 生成
scripts/Makefile.build:kernel/sched/fair.o // 由 fair.c 生成
scripts/Makefile.build:kernel/sched/build_policy.o // 由 build_policy.c 生成
scripts/Makefile.build:kernel/sched/build_utility.o // 由 build_utility.c 生成
ar cDPrST kernel/sched/built-in.a kernel/sched/core.o kernel/sched/fair.o kernel/sched/build_policy.o kernel/sched/build_utility.o // 生成 kernel/sched/built-in.a
scripts/Makefile.build:kernel/sched/modules.order
{ :; } > kernel/sched/modules.order // 由于该目录下没有配置模块,所以生成的 modules.order 为空
scripts/Makefile.build:kernel/... // 其他类似,省略
ar cDPrST kernel/built-in.a kernel/fork.o kernel/sched/built-in.a ... // 生成 kernel/built-in.a
scripts/Makefile.build:kernel/modules.order
scripts/Makefile.build:kernel/sched/modules.order // 在生成 kernel/sched/built-in.a 时,同时生成了 kernel/sched/modules.order,所以这里不用再有其他操作
scripts/Makefile.build:kernel/... // 其他类似,省略
{ cat kernel/sched/modules.order; ... } > kernel/modules.order // 由于该目录及其子目录下没有配置模块,所以生成的 modules.order 为空
scripts/Makefile.build:fs/built-in.a
scripts/Makefile.build:fs
make -f ./scripts/Makefile.build obj=fs need-builtin=1 need-modorder=1 // 该命令会生成 fs/built-in.a 和 fs/modules.order
scripts/Makefile.build:fs/
scripts/Makefile.build:fs/built-in.a
scripts/Makefile.build:fs/open.o
scripts/Makefile.build:fs/ext4/built-in.a
scripts/Makefile.build:fs/... // 其他类似,省略
ar cDPrST built-in.a fs/open.o fs/ext4/built-in.a ... // 生成 built-in.a
scripts/Makefile.build:fs/modules.order
scripts/Makefile.build:fs/efivarfs/modules.order
scripts/Makefile.build:fs/efivarfs
make -f ./scripts/Makefile.build obj=fs/efivarfs need-modorder=1 // 该命令会生成 fs/efivarfs/efivarfs.o, fs/efivarfs/efivarfs.mod, fs/efivarfs/modules.order,该目录下的代码是个模块
scripts/Makefile.build:fs/efivar/
scripts/Makefile.build:fs/efivarfs/efivarfs.o
scripts/Makefile.build:fs/efivarfs/efivarfs.mod // 该文件记录了 fs/efivarfs/efivarfs.o 模块由哪些 .o 文件组成
printf 'fs/efivarfs/inode.o\nfs/efivarfs/file.o\nfs/efivarfs/super.o\nfs/efivarfs/vars.o\n' > fs/efivarfs/efivarfs.mod
ld ... -o fs/efivarfs/efivarfs.o @fs/efivarfs/efivarfs.mod // 将 fs/efivarfs/efivarfs.mod 里记录的 .o 文件,即 inode.o file.o super.o vars.o,链接成 fs/efivarfs/efivarfs.o,该命令是在这些 .o 文件生成之后才会执行
scripts/Makefile.build:fs/efivarfs/efivarfs.o
scripts/Makefile.build:fs/efivarfs/inode.o // 由 inode.c 生成
scripts/Makefile.build:fs/efivarfs/file.o // 由 file.c 生成
scripts/Makefile.build:fs/efivarfs/super.o // 由 super.c 生成
scripts/Makefile.build:fs/efivarfs/vars.o // 由 vars.c 生成
scripts/Makefile.build:fs/efivarfs/efivarfs.mod // 这个上面已经生成过了
scripts/Makefile.build:fs/efivarfs/modules.order
scripts/Makefile.build:fs/efivarfs/efivarfs.o // 这个上面已经生成过了
{ echo fs/efivarfs/efivarfs.o; :; } > fs/efivarfs/modules.order
scripts/Makefile.build:fs/... // 其他类似,省略
{ cat fs/efivarfs/modules.order; ... } > fs/modules.order
scripts/Makefile.build:lib/built-in.a
scripts/Makefile.build:lib
make -f ./scripts/Makefile.build obj=lib need-builtin=1 need-modorder=1 // 该命令会生成 lib/lib.a, lib/built-in.a, lib/modules.order,注意这里额外生成了 lib/lib.a
scripts/Makefile.build:lib/
scripts/Makefile.build:lib/lib.a // 用于生成 lib/lib.a
scripts/Makefile.build:lib/argv_split.o // 由 argv_split.c 生成
scripts/Makefile.build:lib/bug.o // 由 bug.c 生成
scripts/Makefile.build:lib/... // 其他类似,省略
ar cDPrsT lib/lib.a lib/argv_split.o lib/bug.o ... // 生成 lib/lib.a
scripts/Makefile.build:lib/built-in.a // 用于生成 lib/built-in.a,生成方式和以上描述相同
scripts/Makefile.build:lib/modules.order // 用于生成 lib/modules.order,生成方式和以上描述相同
scripts/Makefile.build:arch/x86/lib/built-in.a
scripts/Makefile.build:arch/x86/lib
make -f ./scripts/Makefile.build obj=arch/x86/lib need-builtin=1 need-modorder=1 // 该命令会生成 arch/x86/lib/lib.a, arch/x86/lib/built-in.a, arch/x86/lib/modules.order,注意这里额外生成了 arch/x86/lib/lib.a
scripts/Makefile.build:arch/x86/lib/
scripts/Makefile.build:arch/x86/lib/lib.a // 用于生成 arch/x86/lib/lib.a,生成方式和以上描述相同
scripts/Makefile.build:arch/x86/lib/built-in.a // 用于生成 arch/x86/lib/built-in.a,生成方式和以上描述相同
scripts/Makefile.build:arch/x86/lib/modules.order // 用于生成 arch/x86/lib/modules.order,生成方式和以上描述相同
scripts/Makefile.build:... // 其他类似,省略
ar cDPrST built-in.a kernel/built-in.a fs/built-in.a lib/built-in.a arch/x86/lib/built-in.a ... // 生成 built-in.a
scripts/Makefile.build:./modules.order // 在根目录生成 modules.order
scripts/Makefile.build:kernel/modules.order
scripts/Makefile.build:kernel // 在生成 kernel/built-in.a 时,已经执行过这个任务了,所以在这里,这个任务直接跳过,不用再执行了
scripts/Makefile.build:fs/modules.order // 同上
scripts/Makefile.build:lib/modules.order // 同上
scripts/Makefile.build:arch/x86/lib/modules.order // 同上
scripts/Makefile.build:... // 其他类似,省略
{ cat kernel/modules.order; cat fs/modules.order; cat lib/modules.order; cat arch/x86/lib/modules.order; ... } > modules.order // 把子目录 modules.order 的内容拼接在一起,生成当前目录的 modules.order
ar cDPrST vmlinux.a ./built-in.a lib/lib.a arch/x86/lib/lib.a // 把 built-in.a lib/lib.a arch/x86/lib/lib.a 里的内容合并在一起,生成 vmlinux.a
make -f ./scripts/Makefile.vmlinux_o // 该命令会生成 vmlinux.o, modules.builtin.modinfo, modules.builtin 文件
scripts/Makefile.vmlinux_o:__default
scripts/Makefile.vmlinux_o:vmlinux.o
vmlinux.a // 这个之前已经生成过了
ld ... -o vmlinux.o --whole-archive vmlinux.a --no-whole-archive ... // 生成 vmlinux.o
scripts/Makefile.vmlinux_o:modules.builtin.modinfo
objcopy -j .modinfo -O binary vmlinux.o modules.builtin.modinfo // 把 vmlinux.o 里的 .modinfo 这个 section 里的内容,拷贝到 modules.builtin.modinfo 文件
scripts/Makefile.vmlinux_o:modules.builtin
scripts/Makefile.vmlinux_o:modules.builtin.modinfo // 这个之前已经生成过了
tr '\0' '\n' < modules.builtin.modinfo | ... > modules.builtin // 根据 modules.builtin.modinfo 的内容,生成 modules.builtin 文件,该命令很长,这里只显示了部分,完整命令请查看内核构建时生成的 .modules.builtin.cmd 文件
Makefile:arch/x86/kernel/vmlinux.lds
Makefile:. // 这个任务之前已经执行过了,这里不用再执行,这个任务在构建 arch/x86/kernel 目录时,会生成 arch/x86/kernel/vmlinux.lds 文件
Makefile:modpost
Makefile:vmlinux.o // 这个之前已经生成过了
Makefile:modules_check
Makefile:modules.order
Makefile:. // 这个任务之前已经执行过了,这里不用再执行,它会生成 modules.order 文件
sh ./scripts/modules-check.sh modules.order // 检查是否有同名的模块,如果有就报错
make -f ./scripts/Makefile.modpost
scripts/Makefile.modpost:__modpost
scripts/Makefile.modpost:Module.symvers
./scripts/mod/modpost // 这个工具之前就生成过了
modules.order // 这个文件之前也生成过了
vmlinux.o // 这个之前也生成过了
./scripts/mod/modpost -M -o Module.symvers -T modules.order vmlinux.o // modpost 程序会为 modules.order 里的模块生成对应的 *.mod.c 文件,为 vmlinux.o 生成 .vmlinux.export.c 文件,以及最终生成 Module.symvers 文件
scripts/mod/modpost.c:main // modpost 程序的 main 函数
解析 -M 参数
解析 -o 参数
解析 -T 参数
scripts/mod/modpost.c:read_symbols // 解析 vmlinux.o 中和模块相关的数据
scripts/mod/modpost.c:parse_elf // 解析 vmlinux.o,vmlinux.o 是一个以 elf 格式存储的文件
scripts/mod/modpost.c:new_module // 为 vmlinux.o 创建一个 module 实例,并把它添加的全局 modules 列表里
scripts/mod/modpost.c:handle_symbol // 遍历 vmlinux.o 的符号列表,将未解析的符号,以及一些特殊符号,添加到 module 实例的对应字段里
scripts/mod/file2alias.c:handle_moddevtable // 为模块创建别名
scripts/mod/modpost.c:check_sec_ref // 检查 section 之间的引用是否合法
scripts/mod/modpost.c:section_rela
scripts/mod/modpost.c:check_section_mismatch
scripts/mod/modpost.c:check_export_symbol // 检查内核中使用 EXPORT_SYMBOL 宏导出的符号
scripts/mod/modpost.c:sym_add_exported // 将 EXPORT_SYMBOL 宏定义的符号,添加到 module 实例的 exported_symbols 字段,以及添加到全局符号 hashtable 中
scripts/mod/modpost.c:read_symbols_from_files // 解析 modules.order 里存放的各个模块
scripts/mod/modpost.c:read_symbols // 解析 modules.order 里的某个模块,比如 fs/efivarfs/efivarfs.o,解析方式和之前解析 vmlinux.o 的方式一样,它们使用的都是同一个函数
scripts/mod/modpost.c:check_exports // 遍历 modules.order 里的各个模块,检查模块中未解析的符号,是否在其他模块或内核里,用 EXPORT_SYMBOL 宏定义了
scripts/mod/modpost.c:write_vmlinux_export_c_file // 将 vmlinux.o 中,使用 EXPORT_SYMBOL 宏导出的符号,写到 .vmlinux.export.c 文件里
scripts/mod/modpost.c:write_mod_c_file // 为 modules.order 里的各个模块,创建对应的 *.mod.c 文件,比如为 fs/efivarfs/efivarfs.o 模块,创建 fs/efivarfs/efivarfs.mod.c 文件,该文件记录了这个模块的各种信息
scripts/mod/modpost.c:write_dump // 将 vmlinux.o 以及 modules.order 里的各个模块,使用 EXPORT_SYMBOL 导出的符号,写到 Module.symvers 文件里
make -f ./scripts/Makefile.vmlinux
scripts/Makefile.vmlinux:__default
scripts/Makefile.vmlinux:vmlinux
scripts/Makefile.vmlinux:.vmlinux.export.o // 由 .vmlinux.export.c 生成,而 .vmlinux.export.c 是由之前的 modpost 命令生成
scripts/Makefile.vmlinux:vmlinux
scripts/link-vmlinux.sh // 这是一个提前写好的 shell 脚本
vmlinux.o // 这个是之前生成好的
arch/x86/kernel/vmlinux.lds // 这个也是之前生成好的
scripts/link-vmlinux.sh "ld" "-m elf_x86_64 ..." "--emit-relocs ..." // 该命令会生成 vmlinux 和 System.map
true > .tmp_vmlinux0.syms // 生成一个空的 .tmp_vmlinux0.syms 文件
kallsyms .tmp_vmlinux0.syms .tmp_vmlinux0.kallsyms
scripts/kallsyms --all-symbols --absolute-percpu .tmp_vmlinux0.syms > .tmp_vmlinux0.kallsyms.S // 执行 kallsyms 程序,生成 .tmp_vmlinux0.kallsyms.S,kallsyms 程序是之前生成好的
gcc ... -c -o .tmp_vmlinux0.kallsyms.o .tmp_vmlinux0.kallsyms.S // 把 .tmp_vmlinux0.kallsyms.S 编译成 .tmp_vmlinux0.kallsyms.o
vmlinux_link .tmp_vmlinux1 // 执行 ld 命令,将 vmlinux.o, .vmlinux.export.o, init/version-timestamp.o, .tmp_vmlinux0.kallsyms.o 等都链接到一起,然后写到 .tmp_vmlinux1 文件里
sysmap_and_kallsyms .tmp_vmlinux1
mksysmap .tmp_vmlinux1 .tmp_vmlinux1.syms // 通过 nm 命令,获取 .tmp_vmlinux1 里的所有符号信息,然后经过一定的过滤,把最终数据写到 .tmp_vmlinux1.syms 文件里
kallsyms .tmp_vmlinux1.syms .tmp_vmlinux1.kallsyms // 再次执行 kallsyms 函数,先将 .tmp_vmlinux1.syms 转成 .tmp_vmlinux1.kallsyms.S,再将 .tmp_vmlinux1.kallsyms.S 转成 .tmp_vmlinux1.kallsyms.o,转换逻辑和之前一样
vmlinux_link .tmp_vmlinux2 // 再通过 vmlinux_link 函数,将 vmlinux.o, .vmlinux.export.o, init/version-timestamp.o, .tmp_vmlinux1.kallsyms.o 等都链接到一起,然后写到 .tmp_vmlinux2 文件里
sysmap_and_kallsyms .tmp_vmlinux2 // 和之前一样,再次生成 .tmp_vmlinux2.syms .tmp_vmlinux2.kallsyms.S .tmp_vmlinux2.kallsyms.o 等文件
vmlinux_link vmlinux // 再通过 vmlinux_link 函数,将 vmlinux.o, .vmlinux.export.o, init/version-timestamp.o, .tmp_vmlinux2.kallsyms.o 等都链接到一起,最终生成 vmlinux 文件
mksysmap vmlinux System.map // 使用 nm 命令从 vmlinux 中获取符号列表,过滤后写入到 System.map
make -f ./arch/x86/Makefile.postlink vmlinux
arch/x86/Makefile.postlink:vmlinux
arch/x86/tools/relocs vmlinux > arch/x86/boot/compressed/vmlinux.relocs // 根据 vmlinux 中的 relocation 信息,生成 arch/x86/boot/compressed/vmlinux.relocs 文件,该文件在内核启动时会用到
arch/x86/tools/relocs --abs-relocs vmlinux // 如果 vmlinux 中和 relocation 相关的 section 里存在 absolute relocation,则输出警告信息
objcopy --remove-section='.rel.*' --remove-section='.rel__*' --remove-section='.rela.*' --remove-section='.rela__*' vmlinux // 移除 vmlinux 中和 relocation 相关的 section
arch/x86/Makefile:all
arch/x86/Makefile:bzImage
Makefile:vmlinux // 这个之前已经生成好了
make -f ./scripts/Makefile.build obj=arch/x86/boot arch/x86/boot/bzImage // 该命令会生成最终的 bzImage
arch/x86/boot/Makefile:arch/x86/boot/bzImage
arch/x86/boot/Makefile:arch/x86/boot/setup.bin
arch/x86/boot/Makefile:arch/x86/boot/setup.elf // 由当前目录的代码构建而成
arch/x86/boot/Makefile:arch/x86/boot/header.o // 由对应的 header.S 生成,它是组成 setup.elf 的其中一个文件
arch/x86/boot/Makefile:arch/x86/boot/zoffset.h
arch/x86/boot/Makefile:arch/x86/boot/compressed/vmlinux
make -f ./scripts/Makefile.build obj=arch/x86/boot/compressed arch/x86/boot/compressed/vmlinux // 该命令会在 arch/x86/boot/compressed 目录生成一个压缩版的 vmlinux
arch/x86/boot/compressed/Makefile:arch/x86/boot/compressed/vmlinux
arch/x86/boot/compressed/vmlinux.lds // 由对应的 vmlinux.lds.S 文件生成
arch/x86/boot/compressed/kernel_info.o // 由对应的 kernel_info.S 文件生成
arch/x86/boot/compressed/piggy.o // 由 piggy.S 生成
arch/x86/boot/compressed/Makefile:arch/x86/boot/compressed/piggy.S
arch/x86/boot/compressed/Makefile:arch/x86/boot/compressed/vmlinux.bin.gz
arch/x86/boot/compressed/Makefile:arch/x86/boot/compressed/vmlinux.bin
vmlinux // 这个也是之前生成好的
objcopy -R .comment -S vmlinux arch/x86/boot/compressed/vmlinux.bin
arch/x86/boot/compressed/Makefile:arch/x86/boot/compressed/vmlinux.relocs // 这个是之前就生成好的
cat arch/x86/boot/compressed/vmlinux.bin arch/x86/boot/compressed/vmlinux.relocs | gzip -n -f -9 > arch/x86/boot/compressed/vmlinux.bin.gz // 把 vmlinux.bin 和 vmlinux.relocs 压缩打包在一起,然后写入到 vmlinux.bin.gz 文件
arch/x86/boot/compressed/mkpiggy // 该程序用来生成 piggy.S
arch/x86/boot/compressed/mkpiggy arch/x86/boot/compressed/vmlinux.bin.gz > arch/x86/boot/compressed/piggy.S // 就是把 vmlinux.bin.gz 的数据,内嵌到 piggy.S 里
arch/x86/boot/compressed/... // 其他类似,省略
drivers/firmware/efi/libstub/lib.a // 这个是在构建 vmlinux 时就生成好的
drivers/firmware/efi/libstub/x86-stub.c:efi_pe_entry // 当内核被构建为 uefi 应用时,该函数就是入口函数
ld ... -T arch/x86/boot/compressed/vmlinux.lds arch/x86/boot/compressed/kernel_info.o ... arch/x86/boot/compressed/piggy.o ... drivers/firmware/efi/libstub/lib.a -o arch/x86/boot/compressed/vmlinux
nm arch/x86/boot/compressed/vmlinux | sed -n -e '...' > arch/x86/boot/zoffset.h // 过滤 arch/x86/boot/compressed/vmlinux 中的指定符号,把结果写到 arch/x86/boot/zoffset.h 文件
当内核开启了 CONFIG_EFI_STUB 配置,它会被构建成一个 uefi 应用,此时 header.S 文件里就会指定,内核作为 uefi 应用的入口函数
The EFI Boot Stub
uefi 应用程序的文件格式
objcopy -O binary arch/x86/boot/setup.elf arch/x86/boot/setup.bin
arch/x86/boot/Makefile:arch/x86/boot/vmlinux.bin
arch/x86/boot/Makefile:arch/x86/boot/compressed/vmlinux // 这个之前已经生成过了
objcopy -O binary -R .note -R .comment -S arch/x86/boot/compressed/vmlinux arch/x86/boot/vmlinux.bin
arch/x86/boot/tools/build // 一个工具,由对应的 build.c 生成
arch/x86/boot/tools/build arch/x86/boot/setup.bin arch/x86/boot/vmlinux.bin arch/x86/boot/zoffset.h arch/x86/boot/bzImage // build 工具基本上就是把 arch/x86/boot/setup.bin 和 arch/x86/boot/vmlinux.bin 拼接起来,然后把最终数据写到 arch/x86/boot/bzImage
Makefile:all
Makefile:modules
Makefile:modules_prepare
Makefile:prepare // 这个是之前已经执行过的
make -f ./scripts/Makefile.build obj=scripts scripts/module.lds // 把 scripts/module.lds.S 编译成 scripts/module.lds
Makefile:modules
Makefile:modpost // 这个之前已经执行过了
make -f ./scripts/Makefile.modfinal // 该命令是为 module.order 里记录的所有模块,生成对应的 .ko 文件
scripts/Makefile.modfinal:__modfinal
scripts/Makefile.modfinal:fs/efivarfs/efivarfs.ko
fs/efivarfs/efivarfs.o // 该文件之前就生成好了
scripts/Makefile.modfinal:fs/efivarfs/efivarfs.mod.o // 该文件由 fs/efivarfs/efivarfs.mod.c 生成,而 fs/efivarfs/efivarfs.mod.c 是之前就生成好的
scripts/Makefile.modfinal:.module-common.o // 该文件由 scripts/module-common.c 生成
scripts/module.lds // 该文件之前就生成好了
ld ... -T ./scripts/module.lds -o fs/efivarfs/efivarfs.ko fs/efivarfs/efivarfs.o fs/efivarfs/efivarfs.mod.o .module-common.o // 使用 ld 命令,生成 efivarfs.ko 模块
使用同样的方式,为 modules.order 里记录的其他模块,生成对应的 .ko 文件