【问题标题】:Compiling Kernel code in Linux在 Linux 中编译内核代码
【发布时间】:2011-07-01 03:18:03
【问题描述】:

好的,我正在阅读有关 Linux 内核开发的信息,并且有一些代码 sn-ps 使用内核的数据结构和其他东西。假设我想对它们进行实验,例如有一个非常简单的sn-p:

#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。 sched.h 是正确的文件,好像可以 CTRL+单击它,一个被带到正确的文件。

我是否需要以某种方式包含我的示例文件并从 Makefile 构建整个内核?我只是希望看到它可以构建并且可能会起作用。如果我需要构建整个内核,我将如何实际测试我的东西?

我一定是在做一些非常愚蠢的事情,因为我对内核开发非常陌生。我有点迷茫。

谢谢大家!

【问题讨论】:

    标签: c linux build linux-kernel


    【解决方案1】:

    你不需要编译整个内核,但你至少要创建一个内核模块,这样编译起来要容易得多。你应该看看一个教程,比如this,甚至是一本完整的书,比如this

    请记住,并非所有内核代码都可以移动到模块中——只有那些使用内核的公共(导出)接口的代码。内核核心部分(例如 VM 或调度程序)固有的代码可能无法从内核的其余部分访问。

    另外请记住,不建议在您的开发机器上尝试内核代码 - 轻微的错误很容易导致整个系统崩溃。您应该考虑在单独的虚拟机中尝试您的内核代码,例如在VirtualBox

    一个让事情变得更难的细节:一般来说,您只能在内核中插入一个为其构建的模块。 当且仅当内核相同时,在主机系统上编译的模块可以在测试 VM 上使用,即来自同一发行版的相同内核包版本。考虑到您将要升级主机发行版,我认为在测试系统上构建模块更简单。

    由于您需要full development suite for C,您可能应该安装一个流行的 Linux 发行版。它应该更稳定,您可以访问其用户社区。如果你想减小它的大小,你可以只安装基本系统而不需要 X 服务器或图形应用程序。

    顺便说一句,Netbeans 旨在开发用户空间应用程序。您可能可以将其用于内核代码,但它永远不会像用户空间编程那样适合。事实上,没有 IDE 是真正适合的。内核代码不能从用户空间运行(更不用说使用单独的 VM),这会破坏 IDE 自动执行的正常编辑->编译->运行->调试工作流程循环。

    大多数内核开发人员只使用带有 C 语法高亮功能的增强型编辑器,例如 VimEmacs。 Emacs 实际上是一个 IDE(还有更多),但是,正如我上面提到的,您不能轻松地使用基于 IDE 的工作流程进行内核代码开发。

    【讨论】:

    • 感谢您的详细回答。对通过 VirtualBox 进行内核实验有用的小型 linux 发行版有什么建议吗?我的意思是,在功能齐全的 Ubuntu 上进行测试毫无意义,是吗?并且您对更合适的 IDE 有什么想法吗?
    • 由于您需要开发工具(gcc、make 等),大多数“小型”发行版并不适合。我只会安装一个流行的 linux 发行版,例如 Ubuntu,但没有 X 服务器或图形应用程序。这样可以缩小规模,同时仍然允许您访问主要发行版的社区。​​span>
    • 就 IDE 而言,我认识的大多数内核开发人员(包括我自己)只使用带有 C 语法突出显示的增强型文本编辑器,例如维姆。其他人更喜欢更高级的东西,例如 Emacs。但是由于您无法从用户空间运行内核代码,因此无法使用 IDE 的正常工作流程。
    • 难道我不能在我的主机系统上编译内核模块,然后在 VirtualBox 中的一些轻量级 Linux 发行版上运行它吗?谢谢。
    • thkala,你解释得非常好!谢谢
    【解决方案2】:

    如果您不想构建整个内核,您可以构建一个可加载的内核模块 - 例如。见http://www.linux-tutorial.info/modules.php?name=Howto&pagename=Module-HOWTO

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

            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;
            }
        

        这个例程必须知道如何通过三个结构来销毁inode链另一端的函数指针的调用约定。内核社区非常了解所有这些功能,并且非常乐意在进行更改时修改整个内核结构中的成员名称,但是这种紧密耦合使得在用户空间中单独运行内核部分非常困难。 (相信我,有时我希望我可以在 my 一小部分内核代码上编写测试,这些代码将在用户空间中运行。)

        如果您想尝试一下,现在使用 qemu+kvm 或 virtualbox 或 uml 启动并运行虚拟系统并尝试对内核进行修改并不难。在实时运行的系统上“玩”结构是相当困难的,但它比尝试在用户空间中编译部分内核更可行。

        祝你好运。 :)

        【讨论】:

          【解决方案5】:

          您可能喜欢使用 systemtap 作为内核模块代码的一小部分的包装器:

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

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

          【讨论】:

            猜你喜欢
            • 2016-10-08
            • 1970-01-01
            • 2017-03-09
            • 2013-09-27
            • 1970-01-01
            • 1970-01-01
            • 2011-05-03
            • 2018-04-19
            相关资源
            最近更新 更多