在Linux中编译内核代码

6

好的,我正在阅读关于Linux内核开发的内容,其中有一些代码片段使用了内核的数据结构等。假设我想对它们进行实验,比如说有一个非常简单的代码片段:

#include <../../linux-2.6.37.1/include/linux/sched.h>
struct task_struct *task;
for_each_process(task) {
    printk("%s[%d]\n", task->comm, task->pid);
}

看起来很简单,不是吗?但是我不可能构建这个东西。我正在使用NetBeans。如果可以CTRL +点击它,则sched.h是正确的文件,将导航到正确的文件。

我需要从Makefile中包含我的示例文件并构建整个内核吗?我只想看到它是否能够构建并且可能会工作。如果我需要构建整个内核,那么如何测试我的东西呢?

由于我非常新手,所以一定做错了什么。我有点迷失方向。

谢谢大家!

5个回答

7
您不需要编译整个内核,但您至少需要创建一个内核模块,这要容易得多。您可以查看一些教程,例如这个,或者像这样的完整书籍。
请记住,并非所有内核代码都可以移动到模块中 - 只有使用内核公共(导出的)接口的代码才能移动到模块中。内在于内核核心部分(例如VM或调度程序)的代码可能无法从内核的其余部分访问。
还要记住,在开发机器上尝试内核代码是不建议的 - 一点小错误就可能会使整个系统崩溃。您应该考虑在单独的虚拟机中尝试内核代码,例如在VirtualBox中。
使事情更加困难的细节:通常只能将模块插入为其构建的内核中。在主机系统上编译的模块只能在测试VM上使用如果且仅当内核相同,即来自同一发行版的相同内核包版本。考虑到您将要升级主机发行版,我认为在测试系统上构建模块只是更简单的方法。
由于您需要完整的C开发套件,因此您应该安装其中一个流行的Linux发行版。它应该更稳定,您可以访问其用户社区。如果要减小其大小,则可以仅安装没有X服务器或图形应用程序的基本系统。
顺便说一句,Netbeans是设计用于开发用户空间应用程序的。您可以将其适应内核代码,但它永远不会像适用于用户空间编程一样适合。事实上,没有任何IDE真正适用。内核代码无法从用户空间运行(更不用说使用单独的VM了),这破坏了IDE自动化的正常编辑->编译->运行->调试工作流周期。
大多数内核开发人员只使用带有C语法突出显示的强化编辑器,例如VimEmacs。 Emacs实际上是一个IDE(以及更多),但是正如我上面提到的那样,您不能轻松地使用基于IDE的工作流程进行内核代码开发。

感谢您详细的回答。有没有建议一个小型的Linux发行版,适用于通过VirtualBox进行内核实验?我的意思是,在完整功能的Ubuntu上进行测试没有意义,对吧?您是否有更适合的IDE推荐? - Albus Dumbledore
由于您需要开发工具(gcc、make等),大多数“小型”发行版并不真正适合。我建议只安装流行的Linux发行版,例如Ubuntu,但不安装X服务器或图形应用程序。这将使系统大小保持较小,同时仍然允许您访问主要发行版的社区。 - thkala
就集成开发环境而言,我所认识的大多数内核开发者(包括我自己)都使用带有C语法高亮功能的文本编辑器,比如Vim。其他人则更喜欢一些更先进的工具,例如Emacs。但由于您不能从用户空间运行内核代码,因此无法使用IDE的正常工作流程。 - thkala
我能否不在我的主机系统上编译内核模块,而是在VirtualBox中运行一些轻量级的Linux发行版?谢谢。 - Albus Dumbledore
thkala,你解释得非常好!谢谢 - Albus Dumbledore

1

非常少的内核代码可以以任何形式在内核外运行。大多数内核代码与其他内核代码部分“非常”交织在一起(使用我几年前从同事那里学到的短语来描述过度耦合)。函数“知道”许多结构定义,远离它们正在处理的内容。典型的软件工程人员“讨厌”这样的代码:

    if (unlikely(inode_init_always(sb, inode))) {
            if (inode->i_sb->s_op->destroy_inode)
                    inode->i_sb->s_op->destroy_inode(inode);
            else
                    kmem_cache_free(inode_cachep, inode);
            return NULL;
    }

这个程序必须通过三个结构和链的另一端的函数指针的调用约定来“知道”如何销毁索引节点。内核社区非常了解所有这些函数,并且在内核中进行更改时很高兴修改结构中的成员名称,但是这种紧密耦合使得在用户空间中单独运行内核的部分变得极其困难。(相信我,有时我希望我可以编写在用户空间中运行的内核代码的小部分的测试。)
如果你想玩一下,现在使用qemu+kvm、virtualbox或uml很容易建立一个虚拟系统来尝试对内核进行修改。在运行的实时系统上“玩”结构确实很困难,但与尝试在用户空间中编译内核的部分相比,这要容易得多。
祝你好运。 :)

1

1

你编写、编译和运行的所有代码都作为用户程序在用户模式下运行。内核在内核模式下运行。两种模式是分离的,不能直接看到彼此。它们通过定义的接口进行通信。这些接口是C系统调用(与C库调用相对应)。

要能够访问task_struct结构,你的代码必须在内核模式下运行。最好的选择是编写一个内核模块,并将其加载到内核中。


0

你可能会喜欢使用systemtap作为小块内核模块代码的包装器:

# stap -g -e 'probe begin { your_function() exit() }
%{
#include <linux/whatever.h>
%}
function your_function() %{
   ... insert safe c code here ...
%}'

它也可以自动进行交叉编译(如果使用stap --remote=VIRTMACHINE ...)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接