您的位置:首页 > 运维架构 > Linux

vmlinux是如何炼成的--kernel makefile

2016-03-26 09:53 501 查看
kernel的makefile包含的内容还真是多,我就是想看看要是我自己添加一个目录编译到内核里,要怎么做。

就是这么个不起眼的实验,引发了一堆的故事。

最简单的例子
添加 一个目录,叫test, 添加了test.c 和Makefile。

文件内容很简单,如下。

cat Makefile

#

# Makefile for the linux kernelmakefile experiment.

#

obj-y := test.o

cat test.c

#include <linux/export.h>

int test_global = 0;

然后在主 Makefile中 添加

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

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

最后 make test

make[1]: Nothing to be done for`all'.

HOSTCC arch/x86/tools/relocs

CHK include/linux/version.h

CHK include/generated/utsrelease.h

CC kernel/bounds.s

GEN include/generated/bounds.h

CC arch/x86/kernel/asm-offsets.s

GEN include/generated/asm-offsets.h

CALL scripts/checksyscalls.sh

CC test/test.o

LD test/built-in.o

恩,不错,可以了。

vmlinux是如何炼成的
人总是不知足的,我又开始好奇,这个build的过程究竟是怎么个回事。

好吧,我们知道make后,最终的结果叫vmlinux,那我们就找找这个神奇的东西是怎么

产生的吧。

vmlinux-deps:= $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)

$(sort$(vmlinux-deps)): $(vmlinux-dirs) ;

vmlinux:scripts/link-vmlinux.sh $(vmlinux-deps) FORCE

ifdefCONFIG_HEADERS_CHECK

$(Q)$(MAKE) -f $(srctree)/Makefile headers_check

endif

ifdef CONFIG_SAMPLES

$(Q)$(MAKE) $(build)=samples

endif

ifdef CONFIG_BUILD_DOCSRC

$(Q)$(MAKE) $(build)=Documentation

endif

+$(call if_changed,link-vmlinux)

vmlinx 基于上面三个目标, 而vmlinux-deps又基于 $(vmlinux-dirs)。 恩,好复杂。

那来看看vmlinux-dirs都包含什么吧。

在主Makefile中看到下面的内容。

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

vmlinux-dirs :=$(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \

$(core-y) $(core-m) $(drivers-y) $(drivers-m) \

$(net-y) $(net-m) $(libs-y) $(libs-m)))

$(vmlinux-dirs): prepare scripts

$(Q)$(MAKE)$(build)=$@

恩,我们把vmlinux-dirs的东东打印出来看看。

vmlinux-dris:init usr arch/x86 kernel mm fs ipc security crypto block test drivers soundfirmware arch/x86/pci arch/x86/power arch/x86/video arch/x86/oprofile net libarch/x86/lib

这样,你是不是明白点了呢。这些都是kernel源代码中子目录。也就是kernel将要挨个的

进入每个子目录,编译~。

那最后这个vmlinux是怎么生成的呢? 怎么样将每个目录下生成的模块链接成一个vmlinux的文件的呢?

看到上面vmlinux目标中,最后一个命令:

+$(call if_changed,link-vmlinux)

哦,原来是调用了cmd_link-vmlinux。这个命令就定义在主Makefile中。

cmd_link-vmlinux = $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux)

打出来看看,长这样。

/bin/bash $< ld -m elf_i386 --emit-relocs --build-id

$< 表示第一个以来目标,那么在vmlinux目标中,第一个目标是scripts/link-vmlinux.sh,
展开后就成为。

/bin/bashscripts/link-vmlinux.sh ld -m elf_i386 --emit-relocs --build-id

额,原来是又调用了一个脚本。。。 好吧, 再进去看看。 发现这么个东东

info LD vmlinux

vmlinux_link"${kallsymso}" vmlinux

vmlinux_link()

{

locallds="${objtree}/${KBUILD_LDS}"

if ["${SRCARCH}" != "um" ]; then

${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o${2} \

-T ${lds}${KBUILD_VMLINUX_INIT} \

--start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1}

else

${CC} ${CFLAGS_vmlinux} -o${2} \

-Wl,-T,${lds}${KBUILD_VMLINUX_INIT} \

-Wl,--start-group \

${KBUILD_VMLINUX_MAIN} \

-Wl,--end-group \

-lutil ${1}

rm -f linux

fi

}

好吧,原来是调用了这个函数。。。 打出来看看吧。
ld -m elf_i386 --emit-relocs --build-id -ovmlinux -T arch/x86/kernel/head_32.o arch/x86/kernel/head32.oarch/x86/kernel/head.o init/built-in.o --start-group usr/built-in.oarch/x86/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.oipc/built-in.o security/built-in.o
crypto/built-in.o block/built-in.otest/built-in.o lib/lib.a arch/x86/lib/lib.alib/built-in.o arch/x86/lib/built-in.o drivers/built-in.o sound/built-in.ofirmware/built-in.o arch/x86/pci/built-in.o arch/x86/power/built-in.oarch/x86/video/built-in.o
net/built-in.o --end-group .tmp_kallsyms2.o

恩,原来真相是这样的。 最后把这么多东西链接起来成为vmlinux。 看到我们添加的test目录了么,它也生成了一个built-in.o,最后链接到了vmlinux中。

$ nm vmlinux | grep test_global

c198d284 B test_global

啊哦,还真有这个symbol!

神秘的built-in.o

在最后的链接过程中,我们可以看到,几乎所有的依赖条件中,都会生成一个built-in.o的文件。 那这个文件,是怎么生成的呢?

$(vmlinux-dirs): prepare scripts

$(Q)$(MAKE)$(build)=$@

从这个规则中可以看到,vmlinux-dir目标是通过下面的make来生成的。展开一下看看。 这个build在scripts/Kbuild.include中。

make -fscripts/Makefile.build obj=$@

对应到test目录 那就是

make -f scripts/Makefile.buildobj=test

这么看来,就要进到scripts/Makefile.build文件了。

PHONY := __build

__build:

__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \

$(if$(KBUILD_MODULES),$(obj-m) $(modorder-target)) \

$(subdir-ym)$(always)

@:

__build是这个makefile的第一个目标,也是默认的目标。这里面藏着一个builtin-target,看着很像,再搜搜。

ifneq($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(subdir-m) $(lib-target)),)

builtin-target := $(obj)/built-in.o

endif

恩 原来这个就是这么多叫built-in.o的原因。但是要生成buit-in.o,必须要以上的这些变量不能全部为空。

那再来看看编译这个built-in.o的规则是什么
quiet_cmd_link_o_target =LD $@

# If the list of objects to link isempty, just create an empty built-in.o

cmd_link_o_target = $(if $(strip$(obj-y)),\

$(LD) $(ld_flags) -r -o $@ $(filter$(obj-y), $^) \

$(cmd_secanalysis),\

rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)

$(builtin-target): $(obj-y) FORCE

$(callif_changed,link_o_target)

targets += $(builtin-target)

恩,基本明白了,就是当obj-y的内容不为空,那么就用ld来链接成一个built-in.o。

但是我试了一下,如果没有obj-y那么,也会生成一个built-in.o,但是用的是别的命令。

如在i386下,用的是

rm -f test/built-in.o; ar rcsDtest/built-in.o

不知道这个是什么高级玩意。

好了,到此为止,基本上一个最上层的框架有了一个概念。 那就先休息一下~

源文档 </article/8321597.html>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: