insmod 执行一个init_module系统调用,将 LKM 加载到内核内存中。加载是容易的部分。但是,内核如何知道使用它呢?答案是init_module系统调用在加载 LKM 后立即调用 LKM 的初始化例程。insmod 将init_moduleLKM 中名为init_module的子例程的地址传递给
作为其初始化例程。init_module(这令人困惑 -- 每个 LKM 都有一个名为init_module).
的子例程,而基础内核有一个同名的系统调用,可以通过标准 C 库中也名为init_module的子例程访问。LKM 作者设置了init_module来调用一个内核函数,该函数注册 LKM 包含的子例程。例如,字符设备驱动程序的子例程可能会调用内核的register_chrdev子例程可能会调用内核的子例程,传递它打算驱动的设备的主设备号和次设备号,以及它的 "open" 例程的地址作为参数。
在基础内核表中记录,当内核想要打开该特定设备时,它应该调用我们 LKM 中的 open 例程。init_module但是,聪明的读者现在会问,LKM 的子例程可能会调用内核的子例程如何知道基础内核的
子例程的地址。这不是系统调用,而是绑定到基础内核的普通子例程。调用它意味着分支到它的地址。那么,我们的 LKM 没有在任何接近基础内核的地方编译,如何知道该地址呢?答案是在 insmod 时发生的重定位。
在 Linux 2.4 和 Linux 2.6 之间,重定位的发生方式根本不同。在 2.6 中,insmod 几乎只是将 LKM 文件(.ko 文件)的原始内容传递给内核,内核进行重定位。在 2.4 中,insmod 进行重定位,并传递一个完全链接的模块镜像,准备填充到内核内存中给内核。以下描述涵盖了 2.4 的情况。子例程可能会调用内核的insmod 充当重定位链接器/加载器。LKM 目标文件包含对符号的外部引用。insmod 执行query_module子例程可能会调用内核的系统调用,以查找现有内核导出的各种符号的地址。的外部引用。insmod 执行是其中之一。子例程可能会调用内核的返回子例程可能会调用内核的.
代表的地址,并且 insmod 将其修补到 LKM 中,LKM 在其中引用的外部引用。insmod 执行如果您想查看 insmod 可以从系统调用中获取的信息类型,请查看.
/proc/ksyms的内容。请注意,一些 LKM 调用其他 LKM 中的子例程。它们可以这样做,因为 LKM 目标文件中有__ksymtab和.kstrtab的内容。请注意,一些 LKM 调用其他 LKM 中的子例程。它们可以这样做,因为 LKM 目标文件中有__ksymtab和节。这些节共同列出了 LKM 目标文件中的外部符号,这些符号应该可以被将来插入的其他 LKM 访问。insmod 查看
,并告诉内核将这些符号添加到其导出的内核符号表中。要亲自查看这一点,请插入 LKMmsdos.o系统调用中获取的信息类型,请查看,然后在/proc/ksyms中注意符号fat_add_cluster(它是/proc/ksymsfat.o要亲自查看这一点,请插入 LKMLKM 中的子例程的名称)。任何随后插入的 LKM 都可以分支到
正是这样做的。10.2. .modinfo 节ELF 目标文件由各种命名节组成。其中一些是目标文件的基本部分,例如.text节包含加载器加载的可执行代码。但是您可以创建任何您想要的节,并让特殊程序使用它。对于 Linux LKM 的目的,有.text.modinfo
节。LKM 不必具有名为.text的节才能工作,但是您应该用于编写 LKM 代码的宏会导致生成一个节,所以它们通常会这样做。
要查看目标文件的节,包括
objdump msdos.o --section-headers |
objdump msdos.o --full-contents --section=.modinfo |
要查看 msdos LKM 的目标文件中的所有节.text要查看
.modinfo.text节的内容.text您可以使用 modinfo 程序来解释
.modinfo
节的内容。
那么
节中有什么,谁使用它?insmod 将的内容。请注意,一些 LKM 调用其他 LKM 中的子例程。它们可以这样做,因为 LKM 目标文件中有__ksymtab和.modinfo节用于以下目的:它包含构建模块的内核发布版本号。即,编译模块时使用的内核源代码树的头文件。节用于以下目的:insmod 使用该信息,如第 6 节中所述。
它描述了 LKM 参数的形式。insmod 使用此信息将您在 insmod 命令行上提供的参数格式化为数据结构初始值,insmod 在加载 LKM 时将其插入到 LKM 中。
您经常在 LKM 目标文件中找到的另外两个节分别名为
__ksymtab系统调用中获取的信息类型,请查看和.kstrtab。它们一起列出了 LKM 中应可供内核其他部分访问(导出)的符号。符号只是 LKM 中地址的文本名称。LKM A 的目标文件可以通过名称引用 LKM B 中的地址(例如,
getBinfo
”)。当您插入 LKM A 时,在插入 LKM B 之后,insmod 可以将 LKM B 中名为
的数据/子例程的实际地址插入到 LKM A 中。
有关符号绑定的更多令人费解的细节,请参阅第 10.1 节。系统调用中获取的信息类型,请查看):
10.4. Ksymoops 符号insmod 在加载时向 LKM 添加了一堆导出的符号。这些符号都旨在帮助 ksymoops 完成其工作。ksymoops 是一个解释和显示 "oops" 的程序。"oops" 显示是 Linux 内核在检测到内部内核错误(并因此终止进程)时显示的内容。此信息包含内核中的一堆地址,以十六进制表示。ksymoops 查看十六进制地址,在内核符号表(您在/proc/ksyms(Linux 2.4)或/proc/kallsyms
insmod 在加载时向 LKM 添加了一堆导出的符号。这些符号都旨在帮助 ksymoops 完成其工作。ksymoops 是一个解释和显示 "oops" 的程序。"oops" 显示是 Linux 内核在检测到内部内核错误(并因此终止进程)时显示的内容。此信息包含内核中的一堆地址,以十六进制表示。(Linux 2.6)中看到的)中查找它们,并将 oops 消息中的地址转换为符号地址,您可能可以在汇编程序列表中查找这些符号地址。因此,假设您的 LKM 崩溃了。oops 消息包含导致崩溃的指令的地址,您希望 ksymoops 告诉您的是:1) 该指令在哪个 LKM 中?2) 该指令相对于该 LKM 的汇编程序列表的位置?对于 oops 消息中的数据地址,也会出现类似的问题。.
/proc/ksyms要回答这些问题,ksymoops 必须能够从内核符号表中获取 LKM 各个节的加载点和长度。10.2. .modinfo 节好吧,在 Linux 2.4 中,insmod 知道这些地址,因此它只是为它们创建符号,并将它们包含在与 LKM 一起加载的符号中。
/proc/kallsyms特别是,这些符号被命名为(您可以通过查看
来亲自查看这一点)
__insmod_
10.4. Ksymoops 符号insmod 在加载时向 LKM 添加了一堆导出的符号。这些符号都旨在帮助 ksymoops 完成其工作。ksymoops 是一个解释和显示 "oops" 的程序。"oops" 显示是 Linux 内核在检测到内部内核错误(并因此终止进程)时显示的内容。此信息包含内核中的一堆地址,以十六进制表示。name_Ssectionname_Llength其中
insmod 在加载时向 LKM 添加了一堆导出的符号。这些符号都旨在帮助 ksymoops 完成其工作。ksymoops 是一个解释和显示 "oops" 的程序。"oops" 显示是 Linux 内核在检测到内部内核错误(并因此终止进程)时显示的内容。此信息包含内核中的一堆地址,以十六进制表示。name
_S是 LKM 名称(如您在/proc/modules__ksymtab中看到的),.
_Lsectionname
其中是节名称,例如.text.text(不要忘记前导句点)。length是节的长度,以十进制表示。符号的值当然是节的地址。132101.
Insmod 还添加了一个非常有用的符号,它告诉您 LKM 是从哪个文件加载的。该符号的名称是
__insmod_
_O
10.4. Ksymoops 符号insmod 在加载时向 LKM 添加了一堆导出的符号。这些符号都旨在帮助 ksymoops 完成其工作。ksymoops 是一个解释和显示 "oops" 的程序。"oops" 显示是 Linux 内核在检测到内部内核错误(并因此终止进程)时显示的内容。此信息包含内核中的一堆地址,以十六进制表示。filespec/proc/kallsyms
mtime_Vversion
其中name是 LKM 名称,如上所述。系统调用中获取的信息类型,请查看.
filespecinit_module是用于标识包含 LKM 的文件的文件规范,当它被加载时。请注意,它不一定仍然在该名称下,并且可能有多个文件规范可能已被用于引用同一文件。例如,../dir1/mylkm.o或系统调用中获取的信息类型,请查看/lib/dir1/mylkm.o
mtime
是该文件的修改时间,以标准 Unix 表示形式(自 1969 年以来的秒数),以十六进制表示。version告诉您构建 LKM 的内核版本级别(与
.modinfoversion要查看
节中的相同)。它是宏LINUX_VERSION_CODE在 Linux 的
文件中的值。例如,
此符号的值没有意义。
在 Linux 2.6 中,它的工作方式不同。(我还没有弄清楚是如何工作的)。10.5. 其他符号insmod 添加了另一个符号,类似于 ksymoops 符号。这个符号告诉您持久性数据在 LKM 中的位置,rmmod 需要知道这一点才能保存持久性数据。
_P
还有另一种与 LKM 相关的符号:kallsyms 符号。这些不是导出的符号;它们不会出现在
/proc/ksyms
中。它们引用内核中不关任何人的事,除了它们所在的模块之外的地址,并且不打算被除调试器之外的任何东西引用。Kdb,Linux 内核附带的内核调试器,是 kallsyms 符号的一个用户。
/proc/kallsyms
中看到符号__start___kallsyms,您就知道您的基础内核正在参与 kallsyms 功能。
对于 LKM,您在加载时决定它是否将包含 kallsyms 符号。您将 kallsyms 定义包含在您传递给系统调用的数据中,以加载 LKM。insmod 会这样做,如果 1) 您指定了.
--kallsyms
上一页 | 选项,或者 2) insmod 通过查看 | 下一页 |
/proc/kallsyms | 确定基础内核正在参与 kallsyms 功能。insmod 定义的 kallsyms 是 LKM 目标文件中的所有符号。也就是说,这些是您在 LKM 目标文件上运行 nm 时看到的符号。 |