构建setup.bin的规则也在/arch/x86/boot目录下的Makefile中:
/arch/x86/boot/Makefile:
setup-y += a20.o bioscall.o cmdline.o copy.o cpu.o cpuflags.o cpucheck.o
setup-y += early_serial_console.o edd.o header.o main.o mca.o memory.o
setup-y += pm.o pmjump.o printf.o regs.o string.o tty.o video.o
setup-y += video-mode.o version.o
......
setup-y += video-vga.o
setup-y += video-vesa.o
setup-y += video-bios.o
......
SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
......
LDFLAGS_setup.elf := -T
$(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
$(call if_changed,ld)
OBJCOPYFLAGS_setup.bin := -O binary
$(obj)/setup.bin: $(obj)/setup.elf FORCE
$(call if_changed,objcopy)
根据setup.bin的构建命令可见,setup.bin是由setup.efl经过objcopy复制而来的。根据构建setup.elf的规则可见,构建setup.elf的命令为cmd_ld,其定义如下:
/scripts/Makefile.lib:
cmd_ld = $(LD) $(LDFLAGS) $(ldflags-y) $(LDFLAGS_$(@F)) \
$(filter-out FORCE,$^) -o $@
这里LD就是链接器,定义在顶层Makefile中:
/Makefile:
LD = $(CROSS_COMPILE)ld
链接器的输出就是规则的目标(“ @ ” ) , 这 里 就 是 s e t u p . e l f 。 “ @”),这里就是setup.elf。“ @”),这里就是setup.elf。“^”也是make的一个自动变量,表示规则的全部依赖,所以这里链接器的输入即是规则的依赖,但是使用make的内置函数filter-out过滤掉了依赖中的伪目标FORCE,因此输入是arch/x86/boot/setup.ld和$(SETUP_OBJS)。其中,setup.ld是传递给链接器的链接脚本;SETUP_OBJS对应的则是变量setup-y中记录的目标文件,只不过使用make的内置函数addprefix在这些文件前面中添加了一个前缀,目的是在顶层目录中能找到这些目标文件。
这里我们看到了kbuild的一个约定,虽然都在arch/x86/boot目录下,但是引用原本就存在的文件setup.ld使用的是变量src,而引用动态创建的SETUP_OBJS则使用了变量obj。
将上述变量替换到cmd_ld,cmd_ld最后展开为:
cmd_ld = i686-none-linux-gnu-ld –T arch/x86/boot/setup.ld \
arch/x86/boot/a20.o arch/x86/boot/bioscall.o ...\
–o arch/x86/boot/setup.elf
也就说,链接器依照链接脚本setup.ld,将arch/x86/boot目录下的目标文件a20.o、bioscall.o等链接为setup.elf。
但是setup.elf也是ELF格式的,ELF附加的一些信息对内核是没有意义的,所以kbuild也将ELF格式的setup.elf转换为裸二进制格式的setup.bin。
本文深入解析了在Linux内核源码中,如何通过kbuild系统构建setup.bin的过程。从arch/x86/boot目录下的Makefile入手,详细阐述了setup.bin的构建规则,包括目标文件的链接、ELF格式的转换及最终生成的裸二进制格式。

被折叠的 条评论
为什么被折叠?



