Linux外部模块.ko建立流程

文章欢迎转载,保留联系信息,以便交流。

邮箱:eabi010@gmail.com 

主页:www.ielife.cn(爱嵌论坛——嵌入式技术学习交流) 

博客:blog.csdn.net/ielife

Linux内核如何支持在非源码目录下编译的模块呢?是这篇研究的方向。

一:.查看内核文档Documentation/kbuild/modules.txt

2. How to build external modules
4. Creating a kbuild file for an external module

第2章节说明编译模块所要使用的命令

make -C $KDIR M=`pwd` 

make -C $KDIR M=`pwd` modules

第4章节说明如何写一个外部模块的Makefile

215                 --> filename: Makefile
216                 ifneq ($(KERNELRELEASE),)
217                 # kbuild part of makefile
218                 obj-m  := mydrivers.o
220 
221                 else
222                 # Normal Makefile

224                 KERNELDIR := /lib/modules/`uname -r`/build
225                 all::
226                         $(MAKE) -C $(KERNELDIR) M=`pwd`

232                 endif

以上的Makefile与驱动代码mydrivers.c放在同一目录下,执行make即可

其中,make时先执行else中的双冒号目标all,执行命令make  -C  $(KERNELDIR)  M=`pwd`

make  -C  $(KERNELDIR)表示切换到$(KERNELDIR)目录下执行Makefile文件,因此$(KERNELDIR)需要指定你的源代码树的根目录,根据自己的情况修改224行

而ifneq中的obj-m会在源码树的执行中再次被读取


二:跟踪Makefile的执行流程

由于已经make -C到Linux内核Makefile中,因此分析内核源码目录下的Makefile文件,首先传递进来的M=`pwd`,使得Makefile中会执行

  72 ifdef M
  73   ifeq ("$(origin M)", "command line")
  74     KBUILD_EXTMOD := $(M)
  75   endif
  76 endif

KBUILD_EXTMOD变量会因为make时传递进来的M而被赋值为外部模块所在的目录
KBUILD_EXTMOD不为空,会自动加上modules选项

 137 ifeq ($(KBUILD_EXTMOD),)
 138 _all: all
 139 else
 140 _all: modules
 141 endif

因此会执行modules目标


三:modules目标

内核中有两种编译modules的方法,所以有两个地方有modules的目标规则,一个是基于源码树编译的modules,一个是基于外部编译模块使用的modules

区分两者主要是KBUILD_EXTMOD变量,看Makefile中的内容

559 ifeq ($(KBUILD_EXTMOD),) 

	......

 958 PHONY += modules
 959 modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux)                              
 960         @echo '  Building modules, stage 2.';
 961         $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost

	......

1165 else

	......

1185 KBUILD_MODULES := 1
1186 PHONY += crmodverdir
1187 crmodverdir:
1188         $(Q)mkdir -p $(MODVERDIR)
1189         $(Q)rm -f $(MODVERDIR)/*
1190 
1191 PHONY += $(objtree)/Module.symvers
1192 $(objtree)/Module.symvers:
1193         @test -e $(objtree)/Module.symvers || ( \                                     
1194         echo; \
1195         echo "  WARNING: Symbol version dump $(objtree)/Module.symvers"; \
1196         echo "           is missing; modules will have no dependencies and modversions     ."; \
1197         echo )
1198
1199 module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD))
1200 PHONY += $(module-dirs) modules
1201 $(module-dirs): crmodverdir $(objtree)/Module.symvers
1202         $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)
1203 
1204 modules: $(module-dirs)
1205         @echo '  Building modules, stage 2.';
1206         $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
由于KBUILD_EXTMOD不为空,所以执行1165行的else。在1204行会看到外部模块modules的目标规则,会发现modules的建立需要两个stage

stage1主要完成mydrivers.o,stage2通过Makefile.modpost脚本实现.o文件到.ko文件的转化


四:stage1编译过程

crmodverdir 创建$(MODVERDIR)变量所定义的目录,以下为变量定义处

339 export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions

Module.symvers包含所有被内核构建所导出的符号。

根据以上1185~1202可知道,.o文件是由命令$(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@)

其中build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj,及build = -f $(srctree)/scripts/Makefile.build obj=$(KBUILD_EXTMOD)

即是传递过来的M=所指定的路径,scripts/Makefile.build文件是Linux内核执行命令的接口文件,而顶层的Makefile一般不执行命令。

由于是make -f scripts/Makefile.build会把后面的文件当作Makefile来解析,因此需要查看Makefile.build文件中的内容

 83 __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
 84          $(if $(KBUILD_MODULES),$(obj-m)) \                                            
 85          $(subdir-ym) $(always)
 86         @:
其中,只有obj-m变量被赋值,因为我们外部写的模块会给出obj-m所对应要编译的选项名字
通过script/Makefile.lib的解析,会执行以下部分(静态模式匹配):

200 # Built-in and composite module parts
201 $(obj)/%.o: $(src)/%.c FORCE
202         $(call cmd,force_checksrc)
203         $(call if_changed_rule,cc_o_c)
204 
205 # Single-part modules are special since we need to mark them in $(MODVERDIR)
206 
207 $(single-used-m): $(obj)/%.o: $(src)/%.c FORCE                                         
208         $(call cmd,force_checksrc)
209         $(call if_changed_rule,cc_o_c)
210         @{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
这样就生成了.o文件,其中的变量定义都来自于script/Makefile.lib中,例如if_changed_rule就是其中定义的,
call函数会调用cmd_cc_o_c生成mydrivers.o文件,当然在210行还会生成
相应的mod.c文件

第二个阶段需要Module.symvers,mod.c和stage1阶段的.o文件来生成最终的.ko文件


五:stage2编译过程

模块的第二次编译来自modules规则中的$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost

Makefile.modpost是通过.o生成.ko文件的工具


以上并没有把分析过程的细节,包括Makefile中的语法,及依赖的展开和包含的头文件中定义的相关重要变量和内容做说明,仅是以流程为主,

这些语法在make手册中都会有,其实只要明白了make的语法,顺藤摸瓜就知道外部模块构建的过程了

总结就是,先通过内核的Doc来编写一个外部的Makefile

其次明白内核Makefile的结构,顶层Makefile是确定执行的目标类型

Makefile.build才是真正建立规则的入口,而其中使用到的判断逻辑和值的定义来自Makefile.include和Makefile.lib

最终执行Makefile.modpost编译.o为.ko文件



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要生成一个Linux驱动模块的.ko文件,你需要编写一个makefile并进行交叉编译。 首先,在makefile中指定交叉编译器(CROSS_COMPILE)。例如,你可以使用aarch64-none-linux-gnu-作为交叉编译器。 接下来,指定使用的gcc和ld工具(CC和LD)。这些工具将用于编译和链接你的驱动程序。 然后,你需要指定内核源码目录(KERNELDIR)。这个目录应该是你使用的Linux内核的路径。 还需要指定内核架构(ARCH)。在makefile中,你可以使用ARCH变量来指定。例如,在ARM64架构上,你可以将ARCH设置为arm64。 最后,你需要编写一个目标规则(target rule)来构建驱动模块。在这个规则中,你需要使用$(MAKE)命令来调用内核的make命令,并指定要构建的模块(obj-m)和相关的参数。 例如,你的makefile可能如下所示: ``` CROSS_COMPILE := aarch64-none-linux-gnu- CC := $(CROSS_COMPILE)gcc LD := $(CROSS_COMPILE)ld KERNELDIR := /home/wqs/Linux_SDK/rk3588/kernel CURRENT_PATH := $(shell pwd) ARCH := arm64 obj-m := chrdevbase.o build: kernel_modules kernel_modules: $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules ARCH=$(ARCH) clean: $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean ``` 通过运行make命令,你将能够生成一个Linux驱动模块的.ko文件。这个文件将在当前目录中生成。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [编译内核模块,没有报错,但没有生成.ko文件](https://blog.csdn.net/weixin_36292971/article/details/116619872)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Linux交叉编译生成驱动模块.ko](https://blog.csdn.net/qq_43557686/article/details/126247648)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值