栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux内核学习 篇-00:构建学习环境并运行一个HelloWorld模块

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux内核学习 篇-00:构建学习环境并运行一个HelloWorld模块

“Linux内核学习”系列博文致力为每一位有兴趣学习Linux内核的同志排除学习道路上的障碍,给大家提供最好的帮助,补足市面上各种材料书籍解释不周、报错多等问题。
本系列博文使用的系统版本和编译器版本等均在《Linux内核学习 篇-00》中有详细介绍。


目录

注意事项正文

[一] 环境搭建

[1] 下载安装虚拟机/Ubuntu[2] 安装GCC、VIM等必要工具 [二] 重新编译内核[三] 编写并加载一个helloworld模块 后话

报错


注意事项 本系列博文默认您有一定的:Linux、VIM、C、操作系统基础。为了方便大家的阅读学习,可能会引用其他博文资讯中的内容,所有引用都会将来源附在文末。如果参考本文学习过程中遇到任何报错或问题,欢迎您在评论区发起提问,我会将所有问题的原因以及解决方法完善在对应博文的“后话”中,感谢您的贡献。持续更新中,欢迎点赞收藏关注,三连不迷路。


正文

笔者平时学习生活使用的是Ubuntu,抱着更了解自己的系统,甚至定制属于自己的内核功能等愿望,开始了Linux内核的学习。最初,我直接在工作机上进行各种操作。但是频繁遇到各种问题,诸如:内核编译器版本与模块编译器版本不一致等,这些都会导致内核模块无法加载。
因此笔者建议:即使您平时就是使用Linux的各种发行版进行工作学习,为了保证不破坏自己的环境,请专门搭建一个全新的Linux虚拟机,用来学习接下来的内容。我认为这是完全值得的。

[一] 环境搭建 [1] 下载安装虚拟机/Ubuntu

本系列博文使用的镜像/软件版本如下,可以点击直接下载:
虚拟机:VMware Workstation Pro 16.2.2
Ubuntu:ubuntu-21.10-desktop-amd64
Ubuntu建议用种子,会比HTTP快一点。
安装过程文章众多,不再赘述,不熟悉的同志可以复制搜索:虚拟机安装Ubuntu

[2] 安装GCC、VIM等必要工具

为了尽可能避免奇怪的问题,我决定不进行换源操作,直接进行安装

sudo apt update
sudo apt upgrade
sudo apt install gcc vim make libncurses-dev flex bison libssl-dev libelf-dev dwarves
[二] 重新编译内核

进行内核学习和开发的第一步是配置和重新编译内核,这么做为了一些工具的版本问题,也可以让我们先熟悉一下内核的编译启用过程。
首先运行uname -r查看当前内核版本

然后运行sudo apt-get install linux-source-5.13.0,下载Linux内核代码。请将版本号替换为您自己的内核版本。
下载好后,进入以下目录进行解压和配置:

cd /usr/src/linux-source-5.13.0
sudo tar -xjvf linux-source-5.13.0.tar.bz2
cd linux-source-5.13.0
sudo vim .config

输入/查找字符串:CONFIG_SYSTEM_TRUSTED_KEYS,将此字符串注释掉,然后执行:

sudo make bzImage -j8
sudo make modules -j8
#这里的`-j8`是编译使用的CPU核心数,这个要根据同志们创建虚拟机时分配的核心数来决定。
sudo make modules_install
sudo make install
reboot

要等比较久,只需要等就好了,需要选择的话直接回车。
重启后再次执行uname -r,可以看到此时的查询结果已经与原来的不同了,说明我们确实成功编译并更换了系统的内核:

[三] 编写并加载一个helloworld模块

可以先把home目录清理一下,然后在home目录:

mkdir helloworld
cd helloworld
touch helloworld.c
touch Makefile

然后在helloworld.c中输入以下代码:

#include 
#include 

static int __init helloworld_init(void){
	printk("Hausa_ said hello to Linux kernel");
	return 0;
}

static void __exit helloworld_exit(void){
	printk("Hausa_ said bye to Linux kernel");
}

module_init(helloworld_init);
module_exit(helloworld_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Hausa_ hausahan@gmail.com");
MODULE_DEscriptION("Hausa_'s helloworld module");
MODULE_ALIAS("helloworld");

麻雀虽小,五脏俱全。尽管这个模块只有两个函数,但是却完全可以加载运行。
helloworld_init()函数是该模块初始化/入口函数,helloworld_exit()是销毁/出口函数;
module_init()和module_exit()是linux/init.h中声明的函数,这两个函数告诉内核:某某函数是这个模块的入口/出口函数。
对于最下面一部分大写的函数,是在linux/modules,h中声明的,分别表明了该模块接受的软件许可协议、作者信息、描述以及别名。
printk()函数类似C语言常见的printf,只是前者会将字符串输出到内核模块日志中而不是当前终端上。
接下来我们来编译这个模块,在Makefile中输入以下代码:

KERNELDIR := /lib/modules/$(shell uname -r)/build

CONFIG_MODULE_SIG=n
obj-m := helloworld.o
all:
	$(MAKE) -C $(KERNELDIR) M=$(shell pwd) modules;
clean:
	rm -rf *.o *.ko *.mod *.symvers *.order *.mod

KERNELDIR为正在运行的Linux内核编译目录,obj-m表示要生成的模块
在终端输入make来进行编译。
编译后查看当前目录文件,多了很多文件,其中一个helloworld.ko即为我们需要的文件,我们可以用file和modinfo命令来检查一下编译结果是否正确:
可以看到文件格式为x86-64的ELF文件,并且内核各种信息都正常表示了。
在终端输入sudo insmod helloworld.ko来加载我们的模块,然后可以输入以下命令查看模块打印信息或检查其是否被加载:

sudo dmesg
sudo lsmod | grep helloworld


最后,可以用sudo rmmod helloworld来将模块卸载。
此外,加载模块后,系统会在/sys/module/目录下为模块新建一个目录,对于此例会建helloworld目录,卸载模块后该目录会删除。
本篇结束,有任何报错都可以在评论区反映,我会帮助解决。


后话

如果本文的点赞阅读收藏量还看得过去,我会持续输出同系列文章,感谢大家的支持。

报错
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/748853.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号