vmlinux是如何炼成的--kernel makefile

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

 

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

 

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

 

源文档 <http://blog.csdn.net/richardysteven/article/details/7968002

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值