Linux カーネルモジュールのコンパイルを行った際に何をやっているか調べてみました。
簡単なカーネルモジュール
- まず簡単なカーネルモジュールのソースコードとMakefileを用意します。
/*
* hello.c - The simplest kernel module.
*/
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
int init_module(void)
{
printk(KERN_INFO "Hello world 1.\n");
/*
* A non 0 return means init_module failed; module can't be loaded.
*/
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}
obj-m = hello.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
makeすると、どんなコマンドが実行されるか
簡単なカーネルモージュルをコンパイルするとどんなコマンドが実行されるのか。
make
をすると、カーネルソースに含まれる3つのmakefileが実行されていました。
make -C /lib/modules/3.13.0-62-generic/build M=/home/eggman/tmp/driver/kernelmodule modules
make -f scripts/Makefile.build obj=/home/eggman/tmp/driver/kernelmodule
make -f /usr/src/linux-headers-3.13.0-62-generic/scripts/Makefile.modpost
Makefile で適用されるルール
- 引数Mで指定した値をKBUILD_EXTMODに設定。
- KBUILD_EXTMODからmodule-dirsを設定
- ターゲット $(module-dirs)を生成後に、ターゲット modules を生成する。
- $(build) がどう設定されるかわかりませんが、
-f scripts/Makefile.build obj
が設定されてました。
ifeq ("$(origin M)", "command line")
KBUILD_EXTMOD := $(M)
endif
module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD))
PHONY += $(module-dirs) modules
$(module-dirs): crmodverdir $(objtree)/Module.symvers
$(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)
modules: $(module-dirs)
@$(kecho) ' Building modules, stage 2. ';
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
scripts/Makefile.build で適用されるルール
-
けっこう複雑でした。
-
.cを.oを変換するのは このルールです。
$(obj)/%.o: $(src)/%.c $(recordmcount_source) FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
-
if_changed_rule
はscript/Kbuild.includeで定義されています。
if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ), \
@set -e; \
$(rule_$(1)))
- これは rule_cc_o_c を行います。
define rule_cc_o_c
$(call echo-cmd,checksrc) $(cmd_checksrc) \
$(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \
$(cmd_modversions) \
$(call echo-cmd,record_mcount) \
$(cmd_record_mcount) \
scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \
$(dot-target).tmp; \
rm -f $(depfile); \
mv -f $(dot-target).tmp $(dot-target).cmd
endef
- けっきょき cmd_cc_o_c を実行します。
cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
scripts/Makefile.modpost で適用されるルール
- .koを生成します。
$(modules): %.ko :%.o %.mod.o FORCE
$(call if_changed,ld_ko_o)```
リンカで.oを.koに変換します。
cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \
$(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
-o $@ $(filter-out FORCE,$^)
参考にしたページ
ずっと下書きにあったけど、公開しとく。