为linux内核构建最小的根文件系统-一步一步精简

时间:2022-03-01 06:49:00
linux内核init进程函数的部分代码如下:
01 if ( execute_command)
02 run_init_process( execute_command);
03
04 run_init_process( "/sbin/init");
05 run_init_process( "/etc/init");
06 run_init_process( "/bin/init");
07 run_init_process( "/bin/sh");
08
09 panic( "No init found.  Try passing init= option to kernel.");
10 }

代码中我们看出,linux内核在初始化的最末段,也就是挂载了跟文件系统之后,开始了与根文件系统,也就是用户应用的沟通,我们看到:内核分别尝试了/sbin/init, /etc/init, /bin/init, /bin/sh四个应用的执行,由此可以想到,只要我们准备相应的应用,并且只要满足其中之一,就可以启动系统了,如果任何的一个都没有满足,那么久会出现很经典的内核panic:No init found.  Try passing init= option to kernel.

在此,我们利用现有分析,构建一个可以说是很小的根文件系统,busybox是针对嵌入式开发需求,集各种unix工具于一身的很小很强大的工具集。busybox的编译过程不再赘述,现假设busybox编译后已经生成如下文件夹:

  bin  linuxrc  sbin  usr

其中,linuxrc为程序,bin、sbin、usr为文件夹,其实三个文件夹内绝大部分是程序,并且是指向bin/busybox的链接,也就是所有的命令均由bin/busybox执行

我们看到,内核初始化最后一次尝试的bin/sh, 猜想上来sh并不会跟其它的程序产生关联,所以干脆删除sbin和usr再说,同时linuxrc似乎也不是必须,最多内核报告错误,并不会产生panic,所以精简后,根目录如下(有点裸了:)):

 bin

呵呵,现在想,估计是启动不起来的,为什么呢?起码sh程序或者说busybox要依赖一些动态库,当然可以编译选择静态编译了,那么似乎连什么库都不要,但是我们这里说的最小,并不是文件最少,而是最必须的意思,同时默认busybox编译,采用动态库,所以无论怎么说,lib库是最小根文件系统必须的。所以,添加lib目录,其中的动态库文件来自交叉编译器的lib目录。现在的最小根文件系统如下:

  bin lib

这时候,先别急,我们发现bin目录下,仍然有很多文件,当然也是链向bin/busybox的链接,也就是说,有没有他们没什么关系,那么如果删除他们也没什么影响咯,开始精简bin目录,精简后目录如下:

 busybox  sh

sh程序(到busybox的链接),以及busybox,现在发现,直接输入rm等命令已经不管用了,那么是不是意味着我们的精简结束了呢?因为诸如rm这样的命令只是一个指向busybox的链接,那么就是说我们直接busybox rm这样调用,也可以使用咯,测试一下,果然好用。现在bin目录做到了最小。

回顾一下,我们现在的根文件系统目录如下:其中,bin目录已经最小,下面看看lib目录有没有什么压缩的空间。

  bin lib

lib目录之所以保留到现在,是因为总是怀疑busybox可能用到这个那个库的,所以看看busybox到底用到些什么动态库,pc上执行命令arm-linux-gcc –d busybox,看到以下结果:

01 Dynamic section at offset 0xb5014 contains 22 entries:
02   Tag        Type                         Name/Value
03 0x00000001 ( NEEDED)                      Shared library: [ libcrypt.so.1 ]
04 0x00000001 ( NEEDED)                      Shared library: [ libm.so.6 ]
05 0x00000001 ( NEEDED)                      Shared library: [ libc.so.6 ]
06 0x0000000c ( INIT)                        0xc18c
07 0x0000000d ( FINI)                        0x9e8dc
08 0x00000004 ( HASH)                        0x80e8
09 0x00000005 ( STRTAB)                      0xa410
10 0x00000006 ( SYMTAB)                      0x8b40
11 0x0000000a ( STRSZ)                       3410 ( bytes)
12 0x0000000b ( SYMENT)                      16 ( bytes)
13 0x00000015 ( DEBUG)                       0x0
14 0x00000003 ( PLTGOT)                      0xc50ec
15 0x00000002 ( PLTRELSZ)                    3040 ( bytes)
16 0x00000014 ( PLTREL)                      REL
17 0x00000017 ( JMPREL)                      0xb5ac
18 0x00000011 ( REL)                         0xb55c
19 0x00000012 ( RELSZ)                       80 ( bytes)
20 0x00000013 ( RELENT)                      8 ( bytes)
21 0x6ffffffe ( VERNEED)                     0xb47c
22 0x6fffffff ( VERNEEDNUM)                  3
23 0x6ffffff0 ( VERSYM)                      0xb162
24 0x00000000 ( NULL)                        0x0

我们发现,busybox只使用了libcrypt.so.1 libm.so.6 libc.so.6三个共享库,所以马上精简lib库,考虑可以留下的库文件,以上三个是必须的,那么还有没有必须的呢?经过试验,我们发现,除了上边的3个库以外,ld-linux.so.2不能缺少,猜想可能用于装在,毕竟ld~load,呵呵!到此,lib库精简完成。

这时候,会有人问,那么是不是现在的根文件系统已经可以被挂载,并且最小了呢?现在可以重启开发板了,此时busybox reboot命令已经不能使用,具体原因看输出就知道,重启,下面是结果:

01 Kernel panic - not syncing: Attempted to kill init!
02 Backtrace:
03 [ <c002b600> ] ( dump_backtrace+0x0/0x10c) from [ <c002b740> ] ( dump_stack+0x18/0x1c)
04
05 r6:00000000 r5:c3812c40 r4:c3816000
06 [ <c002b728> ] ( dump_stack+0x0/0x1c) from [ <c003d038> ] ( panic+0x48/0x11c)
07 [ <c003cff0> ] ( panic+0x0/0x11c) from [ <c003f348> ] ( do_exit+0x64/0x59c)
08 r3:c0349c50 r2:c38194e0 r1:c3817f2c r0:c02fcf60
09 r4:c3816000
10 [ <c003f2e4> ] ( do_exit+0x0/0x59c) from [ <c003f910> ] ( do_group_exit+0x90/0xc4)
11 [ <c003f880> ] ( do_group_exit+0x0/0xc4) from [ <c003f95c> ] ( sys_exit_group+0x18/0x2
12 0)
13 r4:000c622c
14 [ <c003f944> ] ( sys_exit_group+0x0/0x20) from [ <c0027da0> ] ( ret_fast_syscall+0x0/0
15 x2c)

结果是不是算灾难性的?至少系统启动失败了!经过无数次烧写文件系统,逐步rm文件,发现console设备文件是必须的,至少bin/sh启动需要,所以添加dev/console,最终的最小根文件系统如下:

1 root@root:/home/works/rootfs_least# ls
2 bin  dev  lib
3 root@root:/home/works/rootfs_least# ls bin
4 busybox  sh
5 root@root:/home/works/rootfs_least# ls dev
6 console
7 root@root:/home/works/rootfs_least# ls lib
8 ld-linux.so.2  libcrypt.so.1  libc.so.6  libm.so.6
9 root@root:/home/works/rootfs_least#

好了,最小的根文件系统已经做好了!方法是:rm reboot rm reboot……分析原因,总结!期待下一篇:为linux内核构建最小的根文件系统-一步一步添加~

--博客使用windows live writer + 发芽网代码高亮写作,感谢windows,发芽网,csdn blog ——