<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>重定位 on 大飞的博客</title>
    <link>https://www.dafei.me/tags/%E9%87%8D%E5%AE%9A%E4%BD%8D/</link>
    <description>Recent content in 重定位 on 大飞的博客</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Thu, 04 Jun 2026 05:00:00 +0000</lastBuildDate>
    <atom:link href="https://www.dafei.me/tags/%E9%87%8D%E5%AE%9A%E4%BD%8D/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>从零写OS（四十八）：内核模块 —— insmod/rmmod</title>
      <link>https://www.dafei.me/posts/os-48-kmod/</link>
      <pubDate>Thu, 04 Jun 2026 05:00:00 +0000</pubDate>
      <guid>https://www.dafei.me/posts/os-48-kmod/</guid>
      <description>&lt;p&gt;动态链接实现之后，内核能加载 PIE 可执行文件了。这章把同样的 ELF 重定位思路用到内核自身：实现&lt;strong&gt;内核模块&lt;/strong&gt;，让内核在运行时动态加载/卸载功能。&lt;/p&gt;
&lt;p&gt;验证：&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/ # insmod hello.ko
hello from module!
/ # rmmod hello
bye from module!
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;ko-文件是什么&#34;&gt;.ko 文件是什么&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;.ko&lt;/code&gt; 是一种特殊的 ELF 文件，类型是 &lt;code&gt;ET_REL&lt;/code&gt;（可重定位目标文件）——也就是还没有链接的 &lt;code&gt;.o&lt;/code&gt; 文件。&lt;/p&gt;
&lt;p&gt;和普通可执行文件的区别：&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;普通 ELF&lt;/th&gt;
          &lt;th&gt;内核模块（.ko）&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;已链接，地址固定&lt;/td&gt;
          &lt;td&gt;未链接，需要重定位&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;用户态运行&lt;/td&gt;
          &lt;td&gt;内核态运行&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;&lt;code&gt;main()&lt;/code&gt; 入口&lt;/td&gt;
          &lt;td&gt;&lt;code&gt;module_init&lt;/code&gt; / &lt;code&gt;module_exit&lt;/code&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;依赖 libc&lt;/td&gt;
          &lt;td&gt;依赖内核导出符号&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;内核符号表ksyms&#34;&gt;内核符号表（ksyms）&lt;/h2&gt;
&lt;p&gt;模块代码需要调用内核函数（比如 &lt;code&gt;kprintf&lt;/code&gt;）。内核把对外开放的函数注册到一张符号表里：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;ksym_t&lt;/span&gt; ksyms[] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    { &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kprintf&amp;#34;&lt;/span&gt;,   (&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;)kprintf   },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    { &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kmalloc&amp;#34;&lt;/span&gt;,   (&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;)kmalloc   },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    { &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kfree&amp;#34;&lt;/span&gt;,     (&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;)kfree     },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    { NULL, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ksym_lookup&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;name) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; ksyms[i].name; i&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;strcmp&lt;/span&gt;(ksyms[i].name, name) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ksyms[i].addr;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;加载流程&#34;&gt;加载流程&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;insmod&lt;/code&gt; 的工作分四步：&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
