写到一半的时候,发现有更新的参考资料,所以重新写一下这里面的内容,之前的参考资料都已经是 2.6 时代的了
参考资料:
给系统加个模块瞧瞧!
首先看到helloworld节的内核模块,遇到一个之前没遇到过的函数 printk ,那我应该看看它是干啥的。
然后发现,这玩意可以在 include/linux/printk.h 找到,有空的时候可以读一下这里面的内容~最后会调用上
int _printk(const char *fmt, ...);
这个那要怎么编译呢?其实只要在当前目录写好内核模块的代码,然后直接调用 Makefile 就可以了,然后内核模块调用当前系统的内核源码~如果你用的是直接克隆的代码,那应该也是同理的。为什么不用上面的buildroot了?可能是突然发现系统自带的内核会更方便吧QAQ
Makefile 里面写好各个操作步骤,比如 -C 指定内核目录,-M指定模块目录
然后一编译就出现了一个错误
看起来现在强制要求内核模块的许可证了呢,那就补上吧,直接加一个
MODULE_LICENSE("WTFPL")
,然后再次make就完事了,会在目录生成若干个文件,可以通过 modinfo hello-1.ko 来看这个内核模块文件的一些细节。可以看到刚刚设置的LICENSE已经有显示了,当然也可以继续写上一些作者之类的信息。然后就可以尝试插入一下了。
那我们再尝试修改一下返回值为非0值,会发生什么呢?
看到了十分眼熟的报错,之前在折腾像mesa之类的东西的时候也遇到过类似的东西,不过目前还不知道怎么这些内容(coredumpctl之类的)
我不要你的名字,我要我的名字
参考资料说,这个函数名其实并不是固定要求的,其实你也可以根据自己的喜欢使用自己的函数名,只要记得使用
module_init
和 module_exit
登记一下就行~然后我们可以和
linux/drivers/char/Makefile
做对比,我们makefile用的是 obj-m ,而这个文件用的是 obj-y ,甚至还有一些用 obj-$(CONFIG_TTY_PRINTK)
,其实就是设置CONFIG_选项为y还是m的区别,也就是到底要不要预置到内核的二进制中。哎呀,你为什么要给我塞初始化和退出宏?
在这章里面,可以留意到参考资料给代码加了一个
__init
和 __exit
宏,那它到底是干嘛的呢?又是在哪里写下它的规则的呢?我们可以看一下内核代码的
include/linux/init.h
看起来它是用来定义段地址的?那行,我们编译出来的时候再看看。编译完成后,使用
readelf -S hello-3.ko
查看其内容:是喔,看起来__init 定义后,就有
.init.text
的定义了,重新看hello-2.ko,你会发现本来是没有的。模块是我写的,你要做什么?!
虽然教程中有写,可以用
MODULE_AUTHOR
来声明模块作者,但我用 grep -rn "MODULE_AUTHOR" .
看了一下,似乎并没有找到这么用的人,这是为什么呢?这是因为,你用dnf装的所谓的内核代码,并不是完整的内核代码,它只包含一些必要的,能让你编译内核模块用的一些代码,还有一些头文件,所以你当然就不能在这里找到作者信息咯~你得下载完整的内核代码再这样找,就能找到了。
咦,装载模块的时候我是不是可以传点东西……
模块装载的时候当然可以传变量,而且还是在 insmod 的时候就可以传!
先声明类似
static int myint=420;
然后跑一下这个函数进行一下这些设置然后在insmod的时候设置一下,比如
在加载模块的时候用 pr_info 来打印一下变量就能看到啦~
我感觉其实可以不用写在一块?
其实文件也可以分开写,也就是各个模块方法写在不同的文件上,关键是在 Makefile 上要写一个类似这样的:
为什么内核模块一般不能跨版本使用?
内核模块一般是根据某个源码编译出来的,它会在 vermagic 里存储内核的版本信息,就像下面这样
也就是说,即使内核的主版本号完全一致,因为子版本(比如 EXTRAVERSION)不一致而导致加载不上,加载时要求 vermagic 这个字符串严格保持一致,避免因为内核版本不同而导致系统出现崩溃。即便如此,也可以通过
--force-vermagic
来解决这个问题,但很不安全就是了。发行版的内核一般会放在 /boot/config-* ,厂商自己编的一般就开 /proc/config.gz 并使用 zcat 来看了。
神奇,为啥我可以直接使用 pr_info?
在内核模块通过 insmod 或者 modprobe 被加载的时候,会从内核本身获得需要使用的符号,所以我们并不需要使用IO库来进行信息打印,只需要借助系统本身有的符号就行。这些符号可以在
/proc/kallsyms
看到。我可以怎么看程序的运行过程?
可以通过 strace 看到程序的运行过程,比如可以先写个hello world试试
然后用
gcc -Wall -o hello hello.c
来编译,生成 hello 后,执行 strace ./hello
,会得到下面一串东西,就能看到调用系统调用所执行的一串东西啦其中
write(1, "hello", 5hello)
这行就是将hello输出到终端上。可以输入 man 2 write
来看这些东西的具体用法。其它事
我靠,SSH怎么传vim的剪贴板?
用鼠标框选或者键盘框选对应选块,然后直接输入
"+y
,框选内容就到本机的剪贴板啦~Lazyvim 的一些快捷操作
总开关:空格
切换焦点:CTRL+h j k l
切换buffer窗口:Shift+l
创建文件: :w filename
终端: CTRL+/