这里首先给出编写的源代码程序,后面对每行代码进行一一说明。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
static char * cmd = "";
module_param(cmd, charp, S_IRUGO);
static int __init helloworld_init(void)
{
printk(KERN_ALERT "Hello world module init with cmd %s\n", cmd);
return 0;
}
static void __exit helloworld_exit(void)
{
printk(KERN_ALERT "Hello world module exit\n");
}
module_init(helloworld_init);
module_exit(helloworld_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("o_o");
MODULE_DESCRIPTION("Hello World Module");
MODULE_VERSION("0.0.1");
MODULE_ALIAS("Hi");
包含这个库,在一般的编译器程序中会报错。
原因是因为linux的/usr/include/linux/
目录中并没有init.h这个头文件,但是这对我们kernel内核编程时不影响的。
因为后面我们并不是直接使用gcc对该ker_HelloWorld.c文件进行编译。
static char * cmd = "";
module_param(cmd, charp, S_IRUGO);
声明了一个静态字符指针变量 cmd
,使用 module_param
宏将其注册为内核参数,charp是一个数据类型,表示字符指针类型,权限为 S_IRUGO,即允许读取。
使得内核中的其他函数能够调用该内核参数cmd
static int __init helloworld_init(void)
{
printk(KERN_ALERT "Hello world module init with cmd %s\n", cmd);
return 0;
}
定义一个静态函数,将相应的信息Hello world module init with cmd %s\n
输出到系统日志中。
printk是Linux内核中用于输出信息的一种函数。它的作用类似于用户空间中的printf函数,但它输出的信息不是直接出出到终端等设备,而是通过内核日志缓冲区
输出到系统日志
中。
__init和__initdata告诉内核这些函数和数据只在初始化期间使用,一旦初始化完成,它们就不再需要,从而可以释放掉它们占用的内存,从而提高系统的性能和效率。
所以该函数名称中的__init关键字表示这是一个初始化函数。
static void __exit helloworld_exit(void)
{
printk(KERN_ALERT "Hello world module exit\n");
}
定义一个静态函数,将相应的信息Hello world module exit\n
输出到系统日志中。
__exit告诉内核这些函数只在模块卸载时使用,一旦模块被卸载,它们就不再需要,从而可以释放掉它们占用的内存,从而提高系统的性能和效率。
所以该函数名称中的__exit关键字表示这是一个清理函数,该函数在模块卸载时被调用。
将函数helloworld_init注册为当前内核模块的初始化函数,当这个内核模块被加载到系统中时,内核会自动调用这个函数来完成其初始化工作。
将函数helloworld_exit注册为当前内核模块的退出函数,当这个内核模块被卸载时,内核会自动调用这个函数来完成其退出工作。
MODULE_LICENSE()
是一个 Linux 内核模块中的宏,用于声明模块的许可证信息。
表示该模块的许可证是 GPL(GNU通用公共许可证)。
MODULE_AUTHOR()
是一个 Linux 内核模块中的宏,用于声明模块的作者信息。
表示模块的作者是 “o_o”。
MODULE_DESCRIPTION()
是一个 Linux 内核模块中的宏,用于声明模块的描述信息。
表示该模块的描述信息为 “Hello World Module”。
MODULE_VERSION()
是一个 Linux 内核模块中的宏,用于声明模块的版本号。
表示该模块的版本号为 “0.0.1”。
# Makefile 4.0
obj-m := ker_HelloWorld.o
CURRENT_PATH := $(shell pwd)
LINUX_KERNEL := $(shell uname -r)
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
在Makefile文件中,obj-m是指要编译成内核模块的目标文件名。它通常用于构建Linux内核模块。obj-m表示目标是一个模块,而不是一个可执行文件。该目标文件名的扩展名通常是“.ko”。
第一行指定了要编译的内核模块的文件名,这里是ker_HelloWorld.o。
CURRENT_PATH变量指定了当前目录的路径,它使用shell命令pwd来获取当前路径。
LINUX_KERNEL变量指定了当前系统的内核版本号,它使用uname命令获取。
LINUX_KERNEL_PATH变量指定了Linux内核源代码的路径,它使用Linux内核版本号拼接而成。
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
all规则使用make命令在$LINUX_KERNEL_PATH目录下构建内核模块,M参数指定了模块代码所在的目录是$(CURRENT_PATH)。
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
在上述工作均完成以后,我们在当前目录执行make
命令生成内核模块module
make
在文件目录中看到的一个以.ko
后缀结尾的文件即为内核模块
通过以下命令加载该内核模块
sudo insmod ker_HelloWorld.ko
在通过lsmod
命令查看加载的内核模块,即可发现我们已经将编写的模块加入到内核中
在通过dmesg
查看内核相关信息,可以发现系统内核中打印出来了我们helloworld_init(void)函数打印的内容。
通过以下命令将模块从内核中删除
sudo rmmod ker_HelloWorld
sudo insmod ker_HelloWorld.ko cmd="o_o'"
通过以下指令即可将当前目录所生成的相应模块删除
make clean
文章浏览阅读1.5k次。1,MyUtuils.kt将被调用的文件class MyUtils { fun show(info:String){ println(info) }}fun show(info:String){ println(info)}2,Java文件调用该类,ClientJava.javapublic class ClientJava { public static void main(String[] args) { /** _java 调用kt 对象
文章浏览阅读6.6k次,点赞4次,收藏4次。在进行UDP编程的时候,我们最容易想到的问题就是,一次发送多少bytes好? 当然,这个没有唯一答案,相对于不同的系统,不同的要求,其得到的答案是不一样的,我这里仅对 像ICQ一类的发送聊天消息的情况作分析,对于其他情况,你或许也能得到一点帮助: 首先,我们知道,TCP/IP通常被认为是一个四层协议系统,包括链路层,网络层,运输层,应用层. UDP属于运输层_最大请求报文大小
文章浏览阅读10w+次,点赞14次,收藏18次。代码如下:for /l %a in (0,0,1) do echo hello,world粘贴在cmd命令行窗口中,回车即可无限死循环输出hello,world。如果需要停止,可以按ctrl+c中断。解析通用形式:for /l %variable IN (start,step,end) DO command [command-parameters] 该集表示以增量形式从start到end的一个数字序列。具体到第一段代码,如果是 (0,0,1) 就是从0开始,每次增_cmd装比代码无限循环
文章浏览阅读917次,点赞18次,收藏11次。为了方便有学习需要的朋友,我把资料都整理成了视频教程(实际上比预期多花了不少精力)当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!我希望每一个努力生活的IT工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。
文章浏览阅读2k次,点赞5次,收藏14次。1、写出微分方程函数2、求解function dy=rigid(t,y)dy=zeros(3,1);dy(1)=y(2)*y(3);dy(2)=-y(1)*y(3);dy(3)=-0.51*y(1)*y(2);end%将微分方程写成函数形式,待调用options=odeset('RelTol',1e-4,'AbsTol',[1e-4 1e-4 1e-5]);[T Y]=ode45(@rigid,[0 12],[0 1 1],options);plot(T,Y(:,1),'-',T,Y_ode函数离散
文章浏览阅读3.8w次,点赞41次,收藏180次。==操作符与equals方法的区别_java中==和equals的区别
文章浏览阅读218次。1.官方的建议1.1 电池续航时间优化(Optimizing Battery Life)参考文章:优化电池使用时间已有中文的详细说明,此处做简要说明:(1)监控电池电量和充电状态(Monitoring the Battery Level and Charging State)通过系统广播,获取充电状态和电池电量的变化来调整数据更新等操作;如在充电时,更新数据及应用,在低电量时,减少更新频..._com.tencent.mm:exdevice
文章浏览阅读818次,点赞14次,收藏9次。计算e1=2.718,e5=148.413,e3=20.086,e1+e5+e3=171.217。“人/B 们/E 常/S 说/S 生/B 活/E 是/S 一/S 部/S 教/B 科/M 书/E ”给一段文字做分词标注,标注每个字对应的标号。图中是双向的三层 RNNs,堆叠多层的RNN网络,可以增加模型的参数,提高模型的拟合。双向的 RNN 是同时考虑“过去”和“未来”的信息,输入(黑色点)沿着黑色的实线箭。比如标签0将表示为([1,0,0,0,0,0,0,0,0,0]),标签3将表示为。
文章浏览阅读513次,点赞9次,收藏10次。无法加载DLL"halconxl": 找不到指定的模块。(异常来自HRESULT:0X8007007E)。在exe安装目录中中添加halconxl.dll文件继续运行就了。_c#如何免安装halcon12
文章浏览阅读1k次,点赞11次,收藏9次。你的键盘上应该有两个Ctrl键,按右边的Ctrl解决了。_键盘一直自动按ctrl
文章浏览阅读141次。Linux 命令【6】:cut文章目录一、简介二、命令详解三、实例演示一、简介cut 命令是一个将文本按列进行切分的小工具,它可以指定分隔每列的定界符。二、命令详解命令格式:cut {选项} {文件名}选项:-b :以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。-c :以字符为单位进行分割。-d :自定义分隔符,默认为制表符。-f :与-d一起使用,指定显示哪个区域。-n :取消分割多字节字符。仅和 -b 标志一起使用。如果字符的最后一._cut使用特殊字符为分隔符
文章浏览阅读2.4k次。/** * 播放audio标签视频控制 * */ //等待音频加载完毕 点击每一段录音进行播放 $('.lis').click(function(){ $('.j_voiceCont').show(); var src = $(this).attr("src"); $(this).addClass('c_audiotrack可以设置进度吗