The kernel module programming primer(2)-Necessary Knowledge

2024-04-13 06:08

本文主要是介绍The kernel module programming primer(2)-Necessary Knowledge,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

模块编程属于内核编程,因此,除了对内核相关知识有所了解外,还需要了解与模块相关的知识。

1.应用程序与内核模块的比较
为了加深对内核模块的了解,表一给出应用程序与内核模块程序的比较。
表一应用程序与内核模块程序的比较


C语言应用程序内核模块程序
使用函数Libc内核函数
运行空间用户空间内核空间
运行权限普通用户超级用户
入口函数main()module_init()
出口函数exit()module_exit()
编译Gcc –cMakefile
连接Gccinsmod
运行直接运行insmod
调试Gdbkdbug, kdb,kgdb

从表一我们可以看出,内核模块程序不能调用libc库中的函数,它运行在内核空间,且只有超级用户可以对其运行。另外,模块程序必须通过module_init()module_exit()函数来告诉内核“我来了”和“我走了”。

2内核符号表(如果对以下第2~4点理解上有困难,可以越过

如前所述,Linux内核是一个整体结构,像一个圆球,而模块是插入到内核中的插件。尽管内核不是一个可安装模块,但为了方便起见,Linux把内核也看作一个“母”模块。那么模块与模块之间如何进行交互呢,一种常用的方法就是共享变量和函数。但并不是模块中的每个变量和函数都能被共享,内核只把各个模块中 主要的变量和函数放在一个特定的区段,这些变量和函数就统称为符号。到低哪些符号可以被共享? Linux内核有自己的规定。对于内核这个特殊的母模块,在kernel/ksyms.c中定义了从中可以“移出”的符号,例如进程管理子系统可以“移出”的符号定义如下:

<span style="font-size:18px;">/* 进程管理 */EXPORT_SYMBOL(do_mmap_pgoff);EXPORT_SYMBOL(do_munmap);EXPORT_SYMBOL(do_brk);EXPORT_SYMBOL(exit_mm);…EXPORT_SYMBOL(schedule);EXPORT_SYMBOL(jiffies);EXPORT_SYMBOL(xtime);…</span>

你可能对这些变量和函数已经很熟悉。其中宏定义EXPORT_SYMBOL()本身的含义是“移出符号”。为什么说是“移出”呢?因为这些符号本来是内核内部的符号,通过这个宏放在一个公开的地方,使得装入到内核中的其他模块可以引用它们。

实际上,仅仅知道这些符号的名字是不够的,还得知道它们在内核地址空间中的地址才有意义。因此,内核中定义了如下结构来描述模块的符号:

<span style="font-size:18px;">struct module_symbol
{unsigned long value; /*符号在内核地址空间中的地址*/const char *name; /*符号名*/
};</span>

我们可以从/proc/ksyms文件中读取所有内核模块“移出”的符号,这所有符号就形成内核符号表,其格式如下:

内存地址 符号名 [所属模块]

在模块编程中,可以根据符号名从这个文件中检索出其对应的地址,然后直接访问该地址从而获得内核数据。

第三列“所属模块”指符号所在的模块名,对于从内核这一母模块移出的符号,这一列为空。

模块加载后,2.4内核下可通过 /proc/ksyms、 2.6 内核下可通过/proc/kallsyms查看模块输出的内核符号

3模块依赖

如前所述,内核符号表记录了所有模块可以访问的符号及相应的地址。当一个新的模块被装入内核后,它所声明的某些符号就会被登记到这个表中,而这些符号可能被其他模块所引用,这就引出了模块依赖这个问题。

一个模块A引用另一个模块B所移出的符号,我们就说模块B被模块A引用,或者说模块A依赖模块B。如果要链接模块A,必须先链接模块B。这种模块间相互依赖的关系就叫模块依赖。

4.模块引用计数器

为了确保模块安全地卸载,每个模块都有一个引用计数器。当执行模块所涉及的操作时就递增计数器,在操作结束时就递减这个计数器;另外,当模块B被模块A引用 时,模块B的引用计数就递增,引用结束,计数器递减。什么时候可以卸载这个模块?当然只有这个计数器值为0的时候,例如,当一个文件系统还被安装在系统上时就不能将其卸载,当这个文件系统不再被使用时,引用计数器就为0,于是可以卸载。

四.模块编译

Linux中最重要的软件开发工具是 GCCGCC GNU C C++编译器。但是,在大型的开发项目中,通常有几十到上百个的源文件,如果每次均手工键入 gcc命令进行编译的话,则会非常不方便。因此,人们通常利用 make工具来自动完成编译工作。利用这种自动编译可大大简化开发工作,避免不必要的重新编译。这些工作包括:如果仅修改了某几个源文件,则只重新编译这几个源文件;如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。

1.编译工具make

实际上,make工具通过一个称为 Makefile 的文件来完成并自动维护编译工作。Makefile 需要按照某种语法进行编写,其中说明了如何编译各个源文件并连接生成可执行文件,并定义了源文件之间的依赖关系。下面给出2.6 内核模块的Makefile模板(请参看Makefile的写法)

<span style="font-size:18px;"># Makefile2.6
obj-m += hellomod.o                  #产生hellomod 模块的目标文件
CURRENT_PATH := $(shell pwd)         #模块所在的当前路径
LINUX_KERNEL := $(shell uname -r)    #Linux内核源代码的当前版本
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)  #Linux内核源代码的绝对路径
all:make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules   #编译模块了
clean:make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean     #清理</span>

注意: 在每个命令前(例如make命令前)要键入一个制表符(按TAB键产生)

有了Makefile,执行make命令,会自动形成相关的后缀为.o和.ko文件。
到此,模块编译好了,该把它插入到内核了,
如:

$insmod hellomod.ko

当然,要以系统员的身份才能把模块插入。

成功插入后,可以通过dmesg命令查看,屏幕最后几行的输出就是你程序中输出的内容:Hello,World! from the kernel space…

 
当模块不再需要时,可以通过rmmod命令移去,例如

$rmmod hellomod

这篇关于The kernel module programming primer(2)-Necessary Knowledge的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/899326

相关文章

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

笔记整理—内核!启动!—kernel部分(2)从汇编阶段到start_kernel

kernel起始与ENTRY(stext),和uboot一样,都是从汇编阶段开始的,因为对于kernel而言,还没进行栈的维护,所以无法使用c语言。_HEAD定义了后面代码属于段名为.head .text的段。         内核起始部分代码被解压代码调用,前面关于uboot的文章中有提到过(eg:zImage)。uboot启动是无条件的,只要代码的位置对,上电就工作,kern

【C++ Primer Plus习题】12.2

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "String.h"using namespace std;int main(){String s1(" and I am a

欧拉系统 kernel 升级、降级

系统版本  cat  /etc/os-release  NAME="openEuler"VERSION="22.03 (LTS-SP1)"ID="openEuler"VERSION_ID="22.03"PRETTY_NAME="openEuler 22.03 (LTS-SP1)"ANSI_COLOR="0;31" 系统初始 kernel 版本 5.10.0-136.12.0.

[Linux Kernel Block Layer第一篇] block layer架构设计

目录 1. single queue架构 2. multi-queue架构(blk-mq)  3. 问题 随着SSD快速存储设备的发展,内核社区越发发现,存储的性能瓶颈从硬件存储设备转移到了内核block layer,主要因为当时的内核block layer是single hw queue的架构,导致cpu锁竞争问题严重,本文先提纲挈领的介绍内核block layer的架构演进,然

Kernel 中MakeFile 使用if条件编译

有时需要通过if  else来选择编译哪个驱动,单纯的obj-$(CONFIG_)就不是很方便,下面提供两种参考案例: 案例一: 来源:drivers/char/tpm/Makefileifdef CONFIG_ACPItpm-y += tpm_eventlog.o tpm_acpi.oelseifdef CONFIG_TCG_IBMVTPMtpm-y += tpm_eventlog.o

jupyter在加载pkl文件时报错ModuleNotFoundError: No module named 'pandas.core.internals.managers'; '的解决方法

笔者当看到这个错误的时候一脸懵逼,在pycharm上正常运行的code 放在jupyter就不成了,于是就研究一翻。 一开始以为自己的pkl文件有问题,研究重点放在这里,最后发现不是。 然后取搜索pycharm和jupyter下的python的\Lib\site-packages\pandas\core\internals有什么不同 发现jupyter下没有pandas\core\intern

【NodeJS】Error: Cannot find module 'ms'

转载自:http://blog.csdn.net/echo_ae/article/details/75097004 问题: Error: Cannot find module 'ms'at Function.Module._resolveFilename (module.js:469:15)at Function.Module._load (module.js:417:25)at Module

【虚拟机/服务器】配置ngx_http_empty_gif_module记录

下载Nginx源码 查看Nginx内置模块 1、在可视化界面中 可以看到 ngx_http_empty_gif_module.c 是Nginx的内置模块,不需要再进行安装 2、在bash命令行中 tar nginx 解压后进入nginx目录,./configure --help | grep empty_gif 即可查看我想要的 ngx_http_empty_gif_module