linux内核模块编译方法详解
文章目录
- 前言
- 一、静态加载法
- 1.1 编写驱动程序
- 1.2 将新功能配置在内核中
- 1.3为新功能代码改写Makefile
- 1.4 make menuconfig界面里将新功能对应的那项选择为<*>
- 二、动态加载法
- 2.1 新功能源码与Linux内核源码在同一目录结构下
- 2.2 新功能源码与Linux内核源码不在同一目录结构下
- 2.3 主机ubuntu下使用ko文件
- 2.4 开发板Linux下使用ko文件
- 三、内核模块基础代码解析
- 四、 内核模块的多源文件编程
- 五、 内核模块信息宏
- 总结
前言
本期和大家主要分享的是关于驱动开发中内核模块的编译方法(向内核中增加新功能),主要分为两种方法,静态加载法和动态加载法,两种方法分别有它们各自的优缺点,接下来一起看看吧!
提示:以下是本篇文章正文内容,下面案例可供参考
一、静态加载法
静态加载法:新功能源码与内核源码再同一目录结构下;
1.1 编写驱动程序
在linux-3.14/driver/char/目录下编写myhello.c,文件内容如下:
#include <linux/module.h>
#include <linux/kernel.h>int __init myhello_init(void)
{printk("#####################################################\n");printk("#####################################################\n");printk("#####################################################\n");printk("#####################################################\n");printk("myhello is running\n");printk("#####################################################\n");printk("#####################################################\n");printk("#####################################################\n");printk("#####################################################\n");return 0;
}void __exit myhello_exit(void)
{printk("myhello will exit\n");
}
MODULE_LICENSE("GPL");
module_init(myhello_init);
module_exit(myhello_exit);
1.2 将新功能配置在内核中
(1)进入myhello.c的同级目录
cd ~/fa4412/linux-3.14/drivers/char
vim Kconfig
(2)在39行处添加如下内容:
config MY_HELLO
tristate “This is a hello test”
help
This is a test for kernel new function
其本质是为了在执行make menuconfig产生的图形化界面中添加This is a hello test这一项,这一项被选中即表示MY_HELLO添加到内核中;
1.3为新功能代码改写Makefile
进入myhello.c的同级目录
cd ~/fs4412/linux-3.14/drivers/char
vim Makefile
obj-$(CONFIG_MY_HELLO) += myhello.ko
注意:这里的CONFIG_MY_HELLO中的MY_HELLO应该与1.2中配置Kconfig的名字一致;本质是为了使得新添加的驱动程序myhello.c加入内核编译;
1.4 make menuconfig界面里将新功能对应的那项选择为<*>
这里顺便提一下:
Y–将该功能编译进内核
N–不将该功能编译进内核
M–将该功能编译成可以在需要时动态插入到内核中的模块
cd ~/fs4412/linux-3.14
make menuconfig
make menuconfig如果出错,一般是两个原因:
- libncurses5-dev没安装
- 命令行界面太小(太矮或太窄或字体太大了)
上述操作结束后,接下来回到linux源码顶层目录,进行make uImage操作;紧接着将新生成的内核镜像拷贝到tftp目录下:cp arch/arm/boot/uImage /tftpboot,最终将uImage下载到开发板,会在启动内核的打印信息中观察到:
这表示自己添加的驱动程序已经添加到了内核中;这种方法称为静态加载法;
二、动态加载法
动态加载发:新功能和内核其他源码不一起编译,而是独立编译成内核的插件(内核模块),文件格式为文件.ko
2.1 新功能源码与Linux内核源码在同一目录结构下
-
给新功能代码配置Kconfig
-
给新功能代码改写Makefile
-
make menuconfig 界面里将新功能对应的那项选择成
-
make uImage
-
cp arch/arm/boot/uImage /tftpboot
-
make modules
make modules会在新功能源码的同级目录下生成相应的同名.ko文件(生成的ko文件只适用于开发板linux)
注意此命令执行前,开发板的内核源码已被编译
2.2 新功能源码与Linux内核源码不在同一目录结构下
- cd ~/fs4412
- mkdir mydrivercode
- cd mydrivercode
- cp …/linux-3.14/drivers/char/myhello.c .
- vim Makefile
- make (生成的ko文件适用于主机ubuntu linux)
- make ARCH=arm (生成的ko文件适用于开发板linux,注意此命令执行前,开发板的内核源码已被编译)
file命令可以查看指定ko文件适用于哪种平台,用法:
file ko文件
#结果带x86字样的适用于主机ubuntu linux,带arm字样的适用于开发板linux
2.3 主机ubuntu下使用ko文件
sudo insmod ./???.ko #此处为内核模块文件名,将内核模块插入正在执行的内核中运行 ----- 相当于安装插件
lsmod #查看已被插入的内核模块有哪些,显示的是插入内核后的模块名
sudo rmmod ??? #,此处为插入内核后的模块名,此时将已被插入的内核模块从内核中移除 ----- 相当于卸载插件
sudo dmesg -C #清除内核已打印的信息
dmesg #查看内核的打印信息
2.4 开发板Linux下使用ko文件
#先将生成的ko文件拷贝到/opt/4412/rootfs目录下:
cp ???/???.ko /opt/4412/rootfs
#在串口终端界面开发板Linux命令行下执行
insmod ./???.ko #将内核模块插入正在执行的内核中运行 ----- 相当于安装插件
lsmod #查看已被插入的内核模块有哪些
rmmod ???
#将已被插入的内核模块从内核中移除 ----- 相当于卸载插件
内核随时打印信息,我们可以在串口终端界面随时看到打印信息,不需要dmesg命令查看打印信息
三、内核模块基础代码解析
Linux内核的插件机制——内核模块
类似于浏览器、eclipse这些软件的插件开发,Linux提供了一种可以向正在运行的内核中插入新的代码段、在代码段不需要继续运行时也可以从内核中移除的机制,这个可以被插入、移除的代码段被称为内核模块。
主要解决:
- 单内核扩展性差的缺点
- 减小内核镜像文件体积,一定程度上节省内存资源
- 提高开发效率
- 不能彻底解决稳定性低的缺点:内核模块代码出错可能会导致整个系统崩溃
内核模块的本质:一段隶属于内核的“动态”代码,与其它内核代码是同一个运行实体,共用同一套运行资源,只是存在形式上是独立的。
#include <linux/module.h> //包含内核编程最常用的函数声明,如printk
#include <linux/kernel.h> //包含模块编程相关的宏定义,如:MODULE_LICENSE/*该函数在模块被插入进内核时调用,主要作用为新功能做好预备工作被称为模块的入口函数__init的作用 :
1. 一个宏,展开后为:__attribute__ ((__section__ (".init.text"))) 实际是gcc的一个特殊链接标记
2. 指示链接器将该函数放置在 .init.text区段
3. 在模块插入时方便内核从ko文件指定位置读取入口函数的指令到特定内存位置
*/
int __init myhello_init(void)
{/*内核是裸机程序,不可以调用C库中printf函数来打印程序信息,Linux内核源码自身实现了一个用法与printf差不多的函数,命名为printk (k-kernel)printk不支持浮点数打印*/printk("#####################################################\n");printk("#####################################################\n");printk("#####################################################\n");printk("#####################################################\n");printk("myhello is running\n");printk("#####################################################\n");printk("#####################################################\n");printk("#####################################################\n");printk("#####################################################\n");return 0;
}/*该函数在模块从内核中被移除时调用,主要作用做些init函数的反操作被称为模块的出口函数__exit的作用:
1.一个宏,展开后为:__attribute__ ((__section__ (".exit.text"))) 实际也是gcc的一个特殊链接标记
2.指示链接器将该函数放置在 .exit.text区段
3.在模块插入时方便内核从ko文件指定位置读取出口函数的指令到另一个特定内存位置
*/
void __exit myhello_exit(void)
{printk("myhello will exit\n");
}/*
MODULE_LICENSE(字符串常量);
字符串常量内容为源码的许可证协议 可以是"GPL" "GPL v2" "GPL and additional rights" "Dual BSD/GPL" "Dual MIT/GPL" "Dual MPL/GPL"等, "GPL"最常用其本质也是一个宏,宏体也是一个特殊链接标记,指示链接器在ko文件指定位置说明本模块源码遵循的许可证
在模块插入到内核时,内核会检查新模块的许可证是不是也遵循GPL协议,如果发现不遵循GPL,则在插入模块时打印抱怨信息:myhello:module license 'unspecified' taints kernelDisabling lock debugging due to kernel taint
也会导致新模块没法使用一些内核其它模块提供的高级功能
*/
MODULE_LICENSE("GPL");/*
module_init 宏
1. 用法:module_init(模块入口函数名)
2. 动态加载模块,对应函数被调用
3. 静态加载模块,内核启动过程中对应函数被调用
4. 对于静态加载的模块其本质是定义一个全局函数指针,并将其赋值为指定函数,链接时将地址放到特殊区段(.initcall段),方便系统初始化统一调用。
5. 对于动态加载的模块,由于内核模块的默认入口函数名是init_module,用该宏可以给对应模块入口函数起别名
*/
module_init(myhello_init);/*
module_exit宏
1.用法:module_exit(模块出口函数名)
2.动态加载的模块在卸载时,对应函数被调用
3.静态加载的模块可以认为在系统退出时,对应函数被调用,实际上对应函数被忽略
4.对于静态加载的模块其本质是定义一个全局函数指针,并将其赋值为指定函数,链接时将地址放到特殊区段(.exitcall段),方便系统必要时统一调用,实际上该宏在静态加载时没有意义,因为静态编译的驱动无法卸载。
5.对于动态加载的模块,由于内核模块的默认出口函数名是cleanup_module,用该宏可以给对应模块出口函数起别名
*/
module_exit(myhello_exit);
模块三要素:入口函数 出口函数 MODULE__LICENSE
四、 内核模块的多源文件编程
ifeq ($(KERNELRELEASE),)ifeq ($(ARCH),arm)
KERNELDIR ?= 目标板linux内核源码顶层目录的绝对路径
ROOTFS ?= 目标板根文件系统顶层目录的绝对路径
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
endif
PWD := $(shell pwd)modules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesmodules_install:$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(ROOTFS) modules_installclean:rm -rf *.o *.ko .*.cmd *.mod.* modules.order Module.symvers .tmp_versionselse
obj-m += hello.oendif
Makefile中:
obj-m用来指定模块名,注意模块名加.o而不是.ko
可以用 模块名-objs 变量来指定编译到ko中的所有.o文件名(每个同名的.c文件对应的.o目标文件)
一个目录下的Makefile可以编译多个模块:
添加:obj-m += 下一个模块名.o
五、 内核模块信息宏
MODULE_AUTHOR(字符串常量); //字符串常量内容为模块作者说明MODULE_DESCRIPTION(字符串常量); //字符串常量内容为模块功能说明MODULE_ALIAS(字符串常量); //字符串常量内容为模块别名
这些宏用来描述一些当前模块的信息,可选宏
这些宏的本质是定义static字符数组用于存放指定字符串内容,这些字符串内容链接时存放在.modinfo字段,可以用modinfo命令来查看这些模块信息,用法:
modinfo 模块文件名
总结
本期主要分享的是两种非常重要的内核加载方法,每种方法都有各自的优缺点,在开发中,经常使用动态加载法来提高开发效率;不仅给出了两种加载新内核功能的方法,并且给出了内核驱动的编写基本框架,希望小伙伴们认真掌握理解哦!!!
最后,各位小伙伴们如果喜欢我的分享可以点赞收藏哦,你们的认可是我创作的动力,一起加油!
相关文章:
linux内核模块编译方法详解
文章目录 前言一、静态加载法1.1 编写驱动程序1.2 将新功能配置在内核中1.3为新功能代码改写Makefile1.4 make menuconfig界面里将新功能对应的那项选择为<*> 二、动态加载法2.1 新功能源码与Linux内核源码在同一目录结构下2.2 新功能源码与Linux内核源码不在同一目录结构…...
简介shell的关联数组与普通数组
本文首先介绍shell的关联数组,然后介绍shell的普通数组,最后总结它们的共同语法。 shell的关联数组 定义一个关联数组,并打印它的key-value对 #!/bin/sh# 声明一个关联数组 declare -A HASH_MAP# 给关联数组赋值 HASH_MAP["Tom"…...
玩转Mysql系列 - 第17篇:存储过程自定义函数详解
这是Mysql系列第17篇。 环境:mysql5.7.25,cmd命令中进行演示。 代码中被[]包含的表示可选,|符号分开的表示可选其一。 需求背景介绍 线上程序有时候出现问题导致数据错误的时候,如果比较紧急,我们可以写一个存储来…...
自动驾驶:轨迹预测综述
自动驾驶:轨迹预测综述 轨迹预测的定义轨迹预测的分类基于物理的方法(Physics-based)基于机器学习的方法(Classic Machine Learning-based)基于深度学习的方法(Deep Learning-based)基于强化学习…...
【uniapp/uview】u-datetime-picker 选择器的过滤器用法
引入:要求日期选择的下拉框在分钟显示时,只显示 0 和 30 分钟; <u-datetime-picker :show"dateShow" :filter"timeFilter" confirm"selDateConfirm" cancel"dateCancel" v-model"value1&qu…...
如何使用Docker部署Nacos服务?Nacos Docker 快速部署指南: 一站式部署与配置教程
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...
yocto stm32mp1集成ros
yocto stm32mp1集成ros yocto集成ros下载meta-rosyocto集成rosrootfs验证 yocto集成ros 本章节介绍yocto如何集成ros系统用来作机器人开发。 下载meta-ros 第一步首先需要下载meta-ros layer,meta-ros的链接如下:https://github.com/ros/meta-ros/tre…...
Linux 中的 chroot 命令及示例
Linux/Unix系统中的chroot命令用于更改根目录。Linux/Unix 类系统中的每个进程/命令都有一个称为root 目录的当前工作目录。它更改当前正在运行的进程及其子进程的根目录。 在此类修改的环境中运行的进程/命令无法访问根目录之外的文件。这种修改后的环境称为“ chroot监狱”或…...
oracle的redo与postgreSQL的WAL以及MySQL的binlog区别
Oracle的redo日志、PostgreSQL的WAL(Write-Ahead Log)以及MySQL的binlog(二进制日志)都是数据库的事务日志,但它们在实现和功能上有一些区别。 1. 实现方式: - Oracle的redo日志是通过在事务提交前将事务操作记录到磁盘上的重做日志文件中来实现的。 - PostgreSQL…...
进入低功耗和唤醒
休眠模式 进入休眠模式 如果使用 WFI 指令进入睡眠模式,则嵌套向量中断控制器 (NVIC) 确认的任意外设中断都会 将器件从睡眠模式唤醒。 如果使用 WFE 指令进入睡眠模式,MCU 将在有事件发生时立即退出睡眠模式。唤醒事件可 通过以下方式产生ÿ…...
【多线程】volatile 关键字
volatile 关键字 1. 保证内存可见性2. 禁止指令重排序3. 不保证原子性 1. 保证内存可见性 内存可见性问题: 一个线程针对一个变量进行读取操作,另一个线程针对这个变量进行修改操作, 此时读到的值,不一定是修改后的值,即这个读线…...
【Windows注册表内容详解】
Windows注册表内容详解 第一章节 注册表基础 一、什么是注册表 注册表是windows操作系统、硬件设备以及客户应用程序得以正常运行和保存设置的核心“数据库”,也可以说是一个非常巨大的树状分层结构的数据库系统。 注册表记录了用户安装在计算机上的软件和每个程…...
大数据Hadoop入门之集群的搭建
hadoop的三种运行模式 本地模式:测试本地的hadoop是否能够运行,用来运行官方的代码。伪分布模式:原先有人拿来测试,目前测试都不用这个模式了。完全分布模式:多台服务器组成分布式环境,生产环境使用 分布式主机文件同步命令 sc…...
华为云云耀云服务器L实例评测|基于云服务器的minio部署手册
华为云云耀云服务器L实例评测|基于云服务器的minio部署手册 【软件安装版本】【集群安装(是)(否)】 版本 创建人 修改人 创建时间 备注 1.0 jz jz 2023.9.2 minio华为云耀服务器 一. 部署规划与架…...
龙智携手Atlassian和JFrog举办线下研讨会,探讨如何提升企业级开发效率与质量
2023年9月8日,龙智将携手Atlassian和JFrog于上海举办线下研讨会,以“大规模开发创新:如何提升企业级开发效率与质量”为主题,邀请龙智高级咨询顾问、Atlassian认证专家叶燕秀,紫龙游戏上海研发中心高级项目管理主管叶凯…...
2023数学建模国赛A题定日镜场的优化设计- 全新思路及代码
背景资料关键信息和要点如下: 定日镜:塔式太阳能光热发电站的基本组件,由纵向转轴和水平转轴组成,用于反射太阳光。 定日镜场:由大量的定日镜组成的阵列。 集热器:位于吸收塔顶端,用于收集太…...
CSS笔记(黑马程序员pink老师前端)圆角边框
圆角边框 border-radius:length; 效果显示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Documen…...
水表电表集中远程抄表系统分析
电表水表远程抄表系统石家庄光大远通电气有限公司主要经营自动抄表,远程抄表,集中抄表,新供应信息,是石家庄光大远通电气有限公司自动远程抄表系统集信号采集、网络通信于一体的高性能抄表装置,该系统以485通讯方式读取水表电表的数据,以MBUS通讯方式读取…...
Android 通知
1. 原生Android通知的几种显示方式: 状态栏的图标:发出通知后,通知会先以图标的形式显示在状态栏中。 抽屉式通知栏:用户可以在状态栏向下滑动以打开抽屉式通知栏,并在其中查看更多详情及对通知执行操作。在应用或用户…...
【Unittest】Requests实现小程序项目接口测试
文章目录 一、搭建接口测试框架二、初始化日志三、定义全局变量四、封装接口五、编写测试用例六、生成测试报告 一、搭建接口测试框架 目录结构如下。 二、初始化日志 在utils.py文件中编写如下如下代码,初始化日志。 # 导入app.py全局变量文件 import app import l…...
Mac 搭建本地服务器
文章目录 一、启动服务器二、添加文件到本地服务三、手机/其他电脑 访问本机服务器 MacOS 自带Apatch 服务器。所以我这里选择Apatch服务器搭建 一、启动服务器 在safari中输入 http://127.0.0.1/ ,如果页面出现 it works,则代表访问成功。启动服务器 …...
区块链基础之编写合约二
一、了解solidity中的关键字。 二、了解solidity中的类型。 三、编写合约 1.这里列出一些solidity中的关键字,有哪些。 pragma 作用:是告知编译器如何处理源代码的通用指令(例如, pragma once )。public 作用&#…...
【前端基础】js 如何判断一个值是数组
在JavaScript中,可使用不同的方法来判断一个值是否是一个数组。以下是一些常用的方法: 使用 Array.isArray() 方法: if (Array.isArray(value)) {// 值是一个数组 } else {// 值不是一个数组 }Array.isArray() 方法是最简单和推荐的方法&…...
Linux之NFS服务器
目录 Linux之NFS服务器 简介 NFS背景介绍 生产应用场景 NFS工作原理 NFS工作流程图 流程 NFS的安装 安装nfs服务 安装rpc服务 启动rpcbind服务同时设置开机自启动 启动nfs服务同时设置开机自启动 NFS的配置文件 主配置文件分析 示例 案例 --- 建立NFS服务器&#…...
ES delete_by_query条件删除的几种方式
es 查询删除的几种方式 1.根据id删除 #根据id删除 POST /indexname/_delete_by_query {"query": { "match": {"id": "100000"}} } 2.根据多个id删除 #根据多个id删除 POST /indexname/_delete_by_query {"query": {"…...
1.springboot 集成elasticsearch组件
1.前置条件已经安装和搭建好了elasticsearch中间件 一:项目中引入elasticsearch相关依赖 我安装的elasticsearch版本是7.10.2 对应依赖的版本保持一致 此处省略springboot 搭建及必要的依赖项 <dependency><groupId>org.elasticsearch.client</group…...
【学习笔记】元学习如何解决计算机视觉少样本学习的问题?
目录 1 计算机视觉少样本学习 2 元学习 3 寻找最优初始参数值方法:MAML 3.1 算法步骤 3.2 代码:使用MAML 和 FO-MAML、任务增强完成Few-shot Classification 4 距离度量方法:Siamese Network,ProtoNet,RN 4.1 孪生网络(Sia…...
【C语言】17-函数-3
1. 链接属性 当组成一个程序的各个源文件分别被编译之后,所有的目标文件以及那些从一个或多个函数库中引用的函数将链接在一起,形成可执行程序。然而,如果相同的标识符出现在几个不同的源文件中时,它们是表示同一个实体,还是表示不同的实体?标识符的链接属性决定如何处理…...
人工智能:为你提供的未来工作岗位
随着科技的快速发展,人工智能(Artificial Intelligence,AI)正逐渐渗透到各个领域。本文探讨一下人工智能可以提供的工作岗位,以期帮助大家更好地了解这个新兴行业的就业前景。 文章目录 1 机器学习工程师2 数据科学家3 自然语言处理工程师4 机器视觉工程…...
HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底层实现。
HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底层实现。 HashMap相关问题 1、你用过HashMap吗?什么是HashMap?你为什么用到它?用过,HashMap是基于哈希表的Map接口的非同步实现, 它允许null键…...
兰州市七里河建设局网站/网站推广方案模板
点击“蓝字”关注我们如果你是一个嵌入式工程师,那么入门的第1个例子很可能就是 - 呼吸灯。那在本次视频中,赛灵思嵌入式工程师张超将和大家一起,用最简单的例子展示如何使用Xilinx Zynq Ultra Scale MPSoC器件,在搭载Linux操作系…...
长沙公司网站开发/世界营销大师排名
提出问题: 回调函数是基于C编程的Windows SDK的技术,不是针对C的,程序员可以将一个C函数直接作为回调函数,但是如果试图直接使用C的成员函数作为回调函数将发生错误,甚至编译就不能通过。分析原因:普通的C成…...
广州地铁2号线/seo短视频网页入口
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt205 利用Java反射机制你可以在运行期动态的创建接口的实现。java.lang.reflect.Proxy类就可以实现这一功能。这个类的名字(译者注:Proxy意思为代理)就是为什么把…...
泰兴做网站的公司/平台推广怎么做
久久的望, 长长的盼, 成熟的时候、落下。 是花、非她, 栽在了心口、 生根发芽。 不记得何时浇灌过泪水, 难想起几时为伊人憔悴, 漠然结果的时候, 听见了谁的心在碎。 飘啊、飞啊, 依偎在风的怀里…...
做外贸网站买海外域名/他达拉非片正确服用方法
string strT"aaa";DataClass adatalist.Find(delegate(DataClass pF) { return pF.NamestrT; }); 注:本随笔为本人总结后发布,如果有雷同,纯属巧合本人邮箱:freedomjimgmail.com,如有疑问和交流欢迎发邮件过…...
深圳自适应网站制作/拼多多代运营一般多少钱
Fiddler抓包工具详细教程一 常用的抓包工具详细教程二 Fiddler2.1 简介2.2 Fiddler抓取HTTP请求2.2.1 HTTP代理2.2.2 字段说明2.2.3 Inspectors 查看数据内容2.3 Fiddler抓取HTTPS请求2.4 Fiddler抓取APP的请求2.5 Fiddler抓取APP上的HTTPS请求2.5.1 安装证书抓取HTTPS请求2.5.…...