1. 程式人生 > >為linux核心構建最小的根檔案系統-一步一步精簡

為linux核心構建最小的根檔案系統-一步一步精簡

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 ——