grub boot.img makefile源码分析

本文详细解析了GRUB2系统中boot.img的生成步骤,包括从源文件boot.S到目标文件boot_image-boot.o的编译过程,boot.image的链接配置,以及最终boot.img的生成方式。
摘要由CSDN通过智能技术生成

本章记录grub2中的boot.img是如何生成的,分三部分看。

第一部分-boot_image_OBJECTS

boot_image_OBJECTS
grub-core/Makefile

boot_image_OBJECTS = $(am_boot_image_OBJECTS) \
    $(nodist_boot_image_OBJECTS)
am_boot_image_OBJECTS =  \
    boot/i386/pc/boot_image-boot.$(OBJEXT)

nodist_boot_image_OBJECTS定义空。因此boot_image_OBJECTS只依赖于am_boot_image_OBJECTS。变量OBJEXT为o,boot/i386/pc/boot_image-boot.$(OBJEXT)有两个依赖关系,下面依次来看。

第一个依赖boot_image-boot.$(OBJEXT)

boot/i386/pc/boot_image-boot.$(OBJEXT)
grub-core/Makefile

boot/i386/pc/boot_image-boot.$(OBJEXT): boot/i386/pc/$(am__dirstamp) \
    boot/i386/pc/$(DEPDIR)/$(am__dirstamp)

其中的变量定义如下,

am__dirstamp = $(am__leading_dot)dirstamp
am__leading_dot = .
DEPDIR = .deps-core

再往下看,

boot/i386/pc/$(am__dirstamp):
    @$(MKDIR_P) boot/i386/pc
    @: > boot/i386/pc/$(am__dirstamp)

@表示不向控制台输出信息。MKDIR_P就是创建目录命令。

MKDIR_P = /bin/mkdir -p

-p选项表示可以创建子目录。因此该依赖就是在boot/i386/pc/目录下创建.dirstamp文件。
同理,第二个依赖如下,

boot/i386/pc/$(DEPDIR)/$(am__dirstamp):
    @$(MKDIR_P) boot/i386/pc/$(DEPDIR)
    @: > boot/i386/pc/$(DEPDIR)/$(am__dirstamp)   

该依赖就是在boot/i386/pc/.deps-core目录下创建.dirstamp文件。

因为两个am__dirstamp没有依赖,因此创建.dirstamp文件的目的是保证文件夹boot/i386/pc/或boot/i386/pc/.deps-core/始终存在。

第二个依赖boot_image-boot.o

boot/i386/pc/boot_image-boot.o
grub-core/Makefile

boot/i386/pc/boot_image-boot.o: boot/i386/pc/boot.S
    $(AM_V_CPPAS)$(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(boot_image_CPPFLAGS) $(CPPFLAGS) $(boot_image_CCASFLAGS) $(CCASFLAGS) -MT boot/i386/pc/boot_image-boot.o -MD -MP -MF boot/i386/pc/$(DEPDIR)/boot_image-boot.Tpo -c -o boot/i386/pc/boot_image-boot.o `test -f 'boot/i386/pc/boot.S' || echo '$(srcdir)/'`boot/i386/pc/boot.S
    $(AM_V_at)$(am__mv) boot/i386/pc/$(DEPDIR)/boot_image-boot.Tpo boot/i386/pc/$(DEPDIR)/boot_image-boot.Po

boot_image-boot.o由boot.S文件编译成。
AM_V_CPPAS变量最终为空定义,CCAS变量为TARGET_CC,最终对应gcc。DEFS定义如下,

DEFS = -DHAVE_CONFIG_H

表示引入configure的头文件。
DEFAULT_INCLUDES定义了头文件的默认搜索路径,定义如下,

DEFAULT_INCLUDES = -I. -I$(top_builddir)
top_builddir = ..

注意当前路径为grub-core,因此DEFAULT_INCLUDES表示在grub-core文件夹以及根文件夹(grub-2.02)中搜索头文件。
INCLUDES为空定义,boot_image_CPPFLAGS后面分析。CPPFLAGS定义了宏_FILE_OFFSET_BITS为64。

CPPFLAGS =  -D_FILE_OFFSET_BITS=64

boot_image_CCASFLAGS后面来看。CCASFLAGS定义为空
-MT指定目标文件名为boot_image-boot.o。-MD -MP -MF选项指定将依赖关系写进boot_image-boot.Tpo中。
再指定原文件名为boot.S。
AM_V_at为空定义,am__mv即mv命令。

am__mv = mv -f

表示将依赖文件boot/i386/pc/.deps-core/boot_image-boot.Tpo重命名为boot/i386/pc/.deps-core/boot_image-boot.Po文件。

boot_image_CPPFLAGS

boot_image_CPPFLAGS
grub-core/Makefile

boot_image_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS_IMAGE) 
AM_CPPFLAGS = $(TARGET_CPPFLAGS) $(CPPFLAGS_DEFAULT)

其中CPPFLAGS_IMAGE最终无定义,因此只看TARGET_CPPFLAGS和CPPFLAGS_DEFAULT的定义。

TARGET_CPPFLAGS
grub-core/Makefile

TARGET_CPPFLAGS =  -Wall -W  -DGRUB_MACHINE_PCBIOS=1 -DGRUB_MACHINE=I386_PC -m32 -nostdinc -isystem /usr/lib/gcc/x86_64-linux-gnu/4.8/include -I$(top_srcdir)/include -I$(top_builddir)/include

Wall、W两个选项表示显示所有警告。D选项设置宏定义GRUB_MACHINE_PCBIOS为1,GRUB_MACHINE为I386_PC。m32表示生成32位代码。nostdinc表示只在-I指定的目录中搜索,而不在标准系统目录中搜索头文件。
isystem选项指定的目录在-I之后查找,这里表示在最后查找,但是如果I选项指定了相同的目录,则忽略I选项提供的目录,也即将该目录放在最后查找,总之isystem选项指定的目录是搜索头文件最后的救命稻草。
接下来继续添加头文件的搜索目录,

top_builddir = ..
top_srcdir = ..

两者指向同一个目录,即根文件夹下的include目录。

CPPFLAGS_DEFAULT
grub-core/Makefile

CPPFLAGS_DEFAULT = -DGRUB_FILE=\"$(subst $(srcdir)/,,$<)\" \
    -I$(builddir) -I$(srcdir) -I$(top_builddir) -I$(top_srcdir) \
    -I$(top_srcdir)/include -I$(top_builddir)/include \
    -I$(top_srcdir)/grub-core/lib/libgcrypt-grub/src/

首先定义了GRUB宏,其值为通过subst函数将第一个依赖$<中的所有./替换成空字符。srcdir和builddir的定义如下,根据前面的分析,这里其实最终就引入了一个新的搜索目录,即/grub-core/lib/libgcrypt-grub/src/文件夹。

srcdir=.
builddir = .

boot_image_CCASFLAGS

boot_image_CCASFLAGS
grub-core/Makefile

boot_image_CCASFLAGS = $(AM_CCASFLAGS) $(CCASFLAGS_IMAGE) 
AM_CCASFLAGS = $(TARGET_CCASFLAGS) $(CCASFLAGS_DEFAULT)
CCASFLAGS_IMAGE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)

CCASFLAGS_IMAGE最终定义为空。

TARGET_CCASFLAGS =  -g  -m32 -msoft-float

g选项表示生成调试信息,在编译阶段生成的调试信息会在链接阶段再去掉。m32表示生成32位代码,soft-float 表示使用软件库模拟浮点运算,对应的hard-float则是直接生成浮点运算的指令,使用硬件进行浮点运算。

CCASFLAGS_DEFAULT = $(CPPFLAGS_DEFAULT) -DASM_FILE=1

CPPFLAGS_DEFAULT的定义和前面重复,最后将宏定义ASM_FILE设为1。

第二部分-boot.image

第一部分最终输出了boot_image-boot.o文件,下面来看它的链接过程。

boot.image
grub-core/Makefile

boot.image$(EXEEXT): $(boot_image_OBJECTS) $(boot_image_DEPENDENCIES) $(EXTRA_boot_image_DEPENDENCIES)
    @rm -f boot.image$(EXEEXT)
    $(AM_V_CCLD)$(boot_image_LINK) $(boot_image_OBJECTS) $(boot_image_LDADD) $(LIBS)

EXEEXT变量,boot_image_DEPENDENCIES和EXTRA_boot_image_DEPENDENCIES都为空定义。首先通过rm命令删除grub-core文件夹下可能已经存在的boot.image文件。
最后除了boot_image_LINK变量,剩下所有变量的定义最终都为空,下面来看boot_image_LINK的依赖关系。

boot_image_LINK
grub-core/Makefile

boot_image_LINK = $(CCLD) $(boot_image_CFLAGS) $(CFLAGS) \
    $(boot_image_LDFLAGS) $(LDFLAGS) -o $@

CCLD变量最终的定义为gcc,boot_image_CFLAGS包含了主要的链接参数,后面分析。CFLAGS和LDFLAGS都为空定义,boot_image_LDFLAGS后面分析。

下面首先来看boot_image_CFLAGS的定义:

boot_image_CFLAGS = $(AM_CFLAGS) $(CFLAGS_IMAGE)

首先看CFLAGS_IMAGE,其定义如下,

CFLAGS_IMAGE = $(CFLAGS_PLATFORM) -fno-builtin

CFLAGS_PLATFORM最终定义为空,-fno-builtin表示使用C语言的buildin函数时,需要带上前缀_builtin。AM_CFLAGS定义为TARGET_CFLAGS,如下

TARGET_CFLAGS =  -Os -Wall -W -Wshadow -Wpointer-arith -Wundef -Wchar-subscripts -Wcomment -Wdeprecated-declarations -Wdisabled-optimization -Wdiv-by-zero -Wfloat-equal -Wformat-extra-args -Wformat-security -Wformat-y2k -Wimplicit -Wimplicit-function-declaration -Wimplicit-int -Wmain -Wmissing-braces -Wmissing-format-attribute -Wmultichar -Wparentheses -Wreturn-type -Wsequence-point -Wshadow -Wsign-compare -Wswitch -Wtrigraphs -Wunknown-pragmas -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value  -Wunused-variable -Wwrite-strings -Wnested-externs -Wstrict-prototypes -g -Wredundant-decls -Wmissing-prototypes -Wmissing-declarations  -Wextra -Wattributes -Wendif-labels -Winit-self -Wint-to-pointer-cast -Winvalid-pch -Wmissing-field-initializers -Wnonnull -Woverflow -Wvla -Wpointer-to-int-cast -Wstrict-aliasing -Wvariadic-macros -Wvolatile-register-var -Wpointer-sign -Wmissing-include-dirs -Wmissing-prototypes -Wmissing-declarations -Wformat=2 -march=i386 -m32 -mrtd -mregparm=3 -falign-jumps=1 -falign-loops=1 -falign-functions=1 -freg-struct-return -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow -msoft-float -fno-dwarf2-cfi-asm -mno-stack-arg-probe -fno-asynchronous-unwind-tables -fno-unwind-tables -Qn -fno-stack-protector -Wtrampolines -Werror

这里的选项太多,懒着一一看了。

再看一下boot_image_LDFLAGS的定义,

boot_image_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS_IMAGE) $(TARGET_IMG_LDFLAGS) $(TARGET_IMG_BASE_LDOPT),0x7C00 

AM_LDFLAGS定义为TARGET_LDFLAGS,如下

TARGET_LDFLAGS =  -m32 -Wl,-melf_i386 -Wl,--build-id=none

m32表示生成32位代码。Wl选项告诉编译器将后面的参数传递给链接器,melf_i386选项用来解决链接中兼容问题,具体不清楚。–build-id=style表示在elf文件中创建.note.gnu.build-id段,内部存储了文件标识码用来标识链接文件,–build-id=none表示忽略之前的–build-id配置。

继续看LDFLAGS_IMAGE的定义,

LDFLAGS_IMAGE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-S

LDFLAGS_PLATFORM定义为空,nostdlib表示链接过程中只使用指定的文件,不使用系统启动文件和标注库文件。
TARGET_LDFLAGS_OLDMAGIC定义如下,

TARGET_LDFLAGS_OLDMAGIC = -Wl,-N

N选项表示链接后需要把text和data段的属性设置为可读写,取消data段的对齐。
S选项表示链接后忽略输出文件中所有的调试符号信息。TARGET_IMG_LDFLAGS变量的定义和TARGET_LDFLAGS_OLDMAGIC一致。最后TARGET_IMG_BASE_LDOPT变量的定义很重要,如下

TARGET_IMG_BASE_LDOPT = -Wl,-Ttext

-Ttext 0x7c00等同于–section-start=text=0x7c00,表示将代码段放到绝对地址0x7C00上,这也是为什么当boot.img被安装在第一个扇区后,开机时,BIOS将其装载在0x7c00,并且第一条指令地址为0x7c00。

第三部分boot.img

boot.img
grub-core/Makefile

boot.img: boot.image$(EXEEXT)
    if test x$(TARGET_APPLE_LINKER) = x1; then   $(MACHO2IMG) $< $@; else   $(TARGET_OBJCOPY) $(boot_image_OBJCOPYFLAGS) --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .MIPS.abiflags -R .reginfo -R .rel.dyn -R .note.gnu.gold-version -R .ARM.exidx $< $@; fi

TARGET_APPLE_LINKER在x86下定义为0,因此只看else部分。TARGET_OBJCOPY变量定义为objcopy指令,boot_image_OBJCOPYFLAGS的定义如下,

boot_image_OBJCOPYFLAGS = $(OBJCOPYFLAGS_IMAGE) -O binary 

OBJCOPYFLAGS_IMAGE为空定义,O选项表示使用指定的格式来写输出目标文件,binary表示生成的是二进制文件。–strip-unneeded用于删除所有重定位中不需要的符号信息,R选项表示移除对应名字的section。最终将boot.image文件修改为boot.img文件。

总结

第一步:根据boot.S生成boot_image-boot.o文件。
首先在对应目录下创建.dirstamp文件,然后将boot.S汇编文件编译成boot_image-boot.o,在编译过程中,将依赖关系写进boot_image-boot.Po文件中。
第二步:将boot_image-boot.o文件链接成boot.image文件。
链接选项中最重要的是将代码段定义在内存的绝对地址0x7C00上。
第三步:利用objcopy命令根据boot.image生成boot.img文件。
其中利用-R参数删除一些不必要的section。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值