色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 什么是module 以及如何寫一個(gè)module(轉(zhuǎn))

          什么是module 以及如何寫一個(gè)module(轉(zhuǎn))

          作者: 時(shí)間:2007-05-23 來源:網(wǎng)絡(luò) 收藏
          作 者: 莊榮城

          不知道在什幺時(shí)候, 出現(xiàn)了 module 這種東西,的確,它是 的一大革新。有了 module 之后,寫 device driver 不再是一項(xiàng)惡夢(mèng),修改 kernel 也不再是一件痛苦的事了。因?yàn)槟悴恍枰看我獪y(cè)試 driver 就重新 compile kernel 一次。那簡(jiǎn)直是會(huì)累死人。Module 可以允許我們動(dòng)態(tài)的改變 kernel,加載 device driver,而且它也能縮短我們 driver development 的時(shí)間。在這篇文章里,我將要跟各位介紹一下 module 的原理,以及如何寫一個(gè) module。

          module 翻譯成中文就是,不過,事實(shí)上去翻譯這個(gè)字一點(diǎn)都沒意義。在講之前,我先舉一個(gè)例子。相信很多人都用過 RedHat。在 RedHat 里,我們可以執(zhí)行 sndconfig,它可以幫我們 config 聲卡。config 完之后如果捉得到你的聲卡,那你的聲卡馬上就可以動(dòng)了,而且還不用重新激活計(jì)算機(jī)。這是怎幺做的呢 ? 就是靠module。module 其實(shí)是一般的程序。但是它可以被動(dòng)態(tài)載到 kernel 里成為 kernel的一部分。載到 kernel 里的 module 它具有跟 kernel 一樣的權(quán)力??梢?access 任何 kernel 的 data structure。你聽過 kdebug 嗎 ? 它是用來 debug kernel 的。它就是先將它本身的一個(gè) module 載到 kernel 里,而在 user space 的 gdb 就可以經(jīng)由跟這個(gè) module 溝通,得知 kernel 里的 data structure 的值,除此之外,還可以經(jīng)由載到 kernel 的 module 去更改 kernel 里 data structure。

          我們知道,在寫 C 程序的時(shí)候,一個(gè)程序只能有一個(gè) main。Kernel 本身其實(shí)也是一個(gè)程序,它本身也有個(gè) main,叫 start_kernel()。當(dāng)我們把一個(gè) module 載到 kernel 里的時(shí)候,它會(huì)跟 kernel 整合在一起,成為 kernel 的一部分。請(qǐng)各位想想,那 module 可以有 main 嗎 ? 答案很明顯的,是 No。理由很簡(jiǎn)單。一個(gè)程序只能有一個(gè) main。在使用 module 時(shí),有一點(diǎn)要記住的是 module 是處于被動(dòng)的角色。它是提供某些功能讓別人去使用的。

          Kernel 里有一個(gè)變量叫 module_list,每當(dāng) user 將一個(gè) module 載到 kernel 里的時(shí)候,這個(gè) module 就會(huì)被記錄在 module_list 里面。當(dāng) kernel 要使用到這個(gè) module 提供的 function 時(shí),它就會(huì)去 search 這個(gè) list,找到 module,然后再使用其提供的 function 或 variable。每一個(gè) module 都可以 export 一些 function 或變量來讓別人使用。除此之外,module 也可以使用已經(jīng)載到 kernel 里的 module 提供的 function。這種情形叫做 module stack。比方說,module A 用到 module B 的東西,那在加載 module A 之前必須要先加載 module B。否則 module A 會(huì)無法加載。除了 module 會(huì) export 東西之外,kernel 本身也會(huì) export 一些 function 或 variable。同樣的,module 也可以使用 kernel 所 export 出來的東西。由于大家平時(shí)都是撰寫 user space 的程序,所以,當(dāng)突然去寫 module 的時(shí)候,會(huì)把平時(shí)寫程序用的 function 拿到 module 里使用。像是 printf 之類的東西。我要告訴各位的是,module 所使用的 function 或 variable,要嘛就是自己寫在 module 里,要嘛就是別的 module 提供的,再不就是 kernel 所提供的。你不能使用一般 libc 或 glibc所提供的 function。像 printf 之類的東西。這一點(diǎn)可能是各位要多小心的地方。(也許你可以先 link 好,再載到 kernel,我好象試過,但是忘了)

          剛才我們說到 kernel 本身會(huì) export 出一些 function 或 variable 來讓 module 使用,但是,我們不是萬能的,我們?cè)蹒壑?kernel 有開放那里東西讓我們使用呢 ? 提供一個(gè) command,叫 ksyms,你只要執(zhí)行 ksyms -a 就可以知道 kernel 或目前載到 kernel 里的 module 提供了那些 function 或 variable。底下是我的系統(tǒng)的情形:

          c0216ba0 drive_info_R744aa133
          c01e4a44 boot_cpu_data_R660bd466
          c01e4ac0 EISA_bus_R7413793a
          c01e4ac4 MCA_bus_Rf48a2c4c
          c010cc34 __verify_write_R203afbeb
          . . . . .

          在 kernel 里,有一個(gè) symbol table 是用來記錄 export 出去的 function 或 variable。除此之外,也會(huì)記錄著那個(gè) module export 那些 function。上面幾行中,表示 kernel 提供了 drive_info 這個(gè) function/variable。所以,我們可以在 kernel 里直接使用它,等載到 kernel 里時(shí),會(huì)自動(dòng)做好 link 的動(dòng)作。由此,我們可以知道,module 本身其實(shí)是還沒做 link 的一些 object code。一切都要等到 module 被加載 kernel 之后,link 才會(huì)完成。各位應(yīng)該可以看到 drive_info 后面還接著一些奇怪的字符串。_R744aa133,這個(gè)字符串是根據(jù)目前 kernel 的版本再做些 encode 得出來的結(jié)果。為什幺額外需要這一個(gè)字符串呢 ?

          Linux 不知道從那個(gè)版本以來,就多了一個(gè) config 的選項(xiàng),叫做 Set version number in symbols of module。這是為了避免對(duì)系統(tǒng)造成不穩(wěn)定。我們知道 Linux 的 kernel 更新的很快。在 kernel 更新的過程,有時(shí)為了效率起見,會(huì)對(duì)某些舊有的 data structure 或 function 做些改變,而且一變可能有的 variable 被拿掉,有的 function 的 prototype 跟原來的都不太一樣。如果這種情形發(fā)生的時(shí)候,那可能以前 2.0.33 版本的 module 拿到 2.2.1 版本的 kernel 使用,假設(shè)原來 module 使用了 2.0.33 kernel 提供的變量叫 A,但是到了 2.2.1 由于某些原因必須把 A 都設(shè)成 NULL。那當(dāng)此 module 用在 2.2.1 kernel 上時(shí),如果它沒去檢查 A 的值就直接使用的話,就會(huì)造成系統(tǒng)的錯(cuò)誤。也許不會(huì)整個(gè)系統(tǒng)都死掉,但是這個(gè) module 肯定是很難發(fā)揮它的功能。為了這個(gè)原因,Linux 就在 compile module 時(shí),把 kernel 版本的號(hào)碼 encode 到各個(gè) exported function 和 variable 里。

          所以,剛才也許我們不應(yīng)該講 kernel 提供了 drive_info,而應(yīng)該說 kernel 提供了 driver_info_R744aa133 來讓我們使用。這樣也許各位會(huì)比較明白。也就是說,kernel 認(rèn)為它提供的 driver_info_R744aa133 這個(gè)東西,而不是 driver_info。所以,我們可以發(fā)現(xiàn)有的人在加載 module 時(shí),系統(tǒng)都一直告訴你某個(gè) function 無法 resolved。這就是因?yàn)?kernel 里沒有你要的 function,要不然就是你的 module 里使用的 function 跟 kernel encode 的結(jié)果不一樣。所以無法 resolve。解決方式,要嘛就是將 kernel 里的 set version 選項(xiàng)關(guān)掉,要嘛就是將 module compile 成 kernel 有辦法接受的型式。

          那有人就會(huì)想說,如果 kernel 認(rèn)定它提供的 function 名字叫做 driver_info_R744aa133 的話,那我們寫程序時(shí),是不是用到這個(gè) funnction 的地方都改成 driver_info_R744aa133 就可以了。答案是 Yes。但是,如果每個(gè) function 都要你這樣寫,你不會(huì)覺得很煩嗎 ? 比方說,我們?cè)趯?driver 時(shí),很多人都會(huì)用到 printk 這個(gè) function。這是 kernel 所提供的 function。它的功能跟 printf 很像。用法也幾乎都一樣。是 debug 時(shí)很好用的東西。如果我們 module 里用了一百次 printk,那是不是我們也要打一百次的 printk_Rdd132261 呢 ? 當(dāng)然不是,聰明的人馬上會(huì)想到用 #define printk printk_Rdd132261 就好了嘛。所以啰,Linux 很體貼的幫我們做了這件事。

          如果各位的系統(tǒng)有將 set version 的選項(xiàng)打開的話,那大家可以到 /usr/src/linux/include/linux/modules 這個(gè)目錄底下。這個(gè)目錄底下有所多的 ..ver檔案。這些檔案其實(shí)就是用來做 #define 用的。我們來看看 ksyms.ver 這個(gè)檔案里,里面有一行是這樣子的 :

          #define printk _set_ver(printk)

          set_ver 是一個(gè) macro,就是用來在 printk 后面加上 version number 的。有興趣的朋友可以自行去觀看這個(gè) macro 的寫法。用了這些 ver 檔,我們就可以在 module 里直接使用 printk 這樣的名字了。而這些 ver 檔會(huì)自動(dòng)幫我們做好 #define 的動(dòng)作??墒?,我們可以發(fā)現(xiàn)這個(gè)目錄有很多很多的 ver 檔。有時(shí)候,我們?cè)蹒壑牢覀円艚械?function 是在那個(gè) ver 檔里有定義呢 ? Linux 又幫我們做了一件事。/usr/src/linux/include/linux/modversions.h 這個(gè)檔案已經(jīng)將全部的 ver 檔都加進(jìn)來了。所以在我們的 module 里只要 include 這個(gè)檔,那名字的問題都解決了。但是,在此,我們奉勸各位一件事,不要將 modversions.h 這個(gè)檔在 module 里 include 進(jìn)來,如果真的要,那也要加上以下數(shù)行:

          #ifdef MODVERSIONS
          #include linux/modversions.h>;
          #endif

          加入這三行的原因是,避免這個(gè) module 在沒有設(shè)定 kernel version 的系統(tǒng)上,將 modversions.h 這個(gè)檔案 include 進(jìn)來。各位可以去試試看,當(dāng)你把 set version 的選項(xiàng)關(guān)掉時(shí),modversions.h 和 modules 這個(gè)目錄都會(huì)不見。如果沒有上面三行,那 compile 就不會(huì)過關(guān)。所以一般來講,modversions.h 我們會(huì)選擇在 compile 時(shí)傳給 gcc 使用。就像下面這個(gè)樣子。

          gcc -c -D__KERNEL__ -DMODULE -DMODVERSIONS main.c
          -include usr/src/linux/include/linux/modversions.h

          在這個(gè) command line 里,我們看到了 -D__KERNEL__,這是說要定義 __KERNEL__ 這個(gè) constant。很多跟 kernel 有關(guān)的 header file,都必須要定義這個(gè) constant 才能 include 的。所以建議你最好將它定義起來。另外還有一個(gè) -DMODVERSIONS。這個(gè) constant 我剛才忘了講。剛才我們說要解決 fucntion 或 variable 名字 encode 的方式就是要 include modversions.h,其實(shí)除此之外,你還必須定義 MODVERSIONS 這個(gè) constant。再來就是 MODULE 這個(gè) constant。其實(shí),只要是你要寫 module 就一定要定義這個(gè)變量。而且你還要 include module.h 這個(gè)檔案,因?yàn)?_set_ver 就是定義在這里的。

          講到這里,相信各位應(yīng)該對(duì) module 有一些認(rèn)識(shí)了,以后遇到 module unresolved 應(yīng)該不會(huì)感到困惑了,應(yīng)該也有辦法解決了。

          剛才講的都是使用別人的 function 上遇到的名字 encode 問題。但是,如果我們自己的 module 想要 export 一些東西讓別的 module 使用呢。很簡(jiǎn)單。在 default 上,在你的 module 里所有的 global variable 和 function 都會(huì)被認(rèn)定為你要 export 出去的。所以,如果你的 module 里有 10 個(gè) global variable,經(jīng)由 ksyms,你可以發(fā)現(xiàn)這十個(gè) variable 都會(huì)被 export 出去。這當(dāng)然是個(gè)很方便的事啦,但是,你知道,有時(shí)候我們根本不想把所有的 variable 都 export 出去,萬一有個(gè) module 沒事亂改我們的 variable 怎幺辦呢 ? 所以,在很多時(shí)候,我們都只會(huì)限定幾個(gè)必要的東西 export 出去。在 2.2.1 之前的 kernel (不是很確定) 可以利用 register_symtab 來幫我們。但是,現(xiàn)在更新的版本早就出來了。所以,在此,我會(huì)介紹 kernel 2.2.1 里所提供的。kernel 2.2.1 里提供了一個(gè) macro,叫做 EXPORT_SYMBOL,這是用來幫我們選擇要 export 的 variable 或 function。比方說,我要 export 一個(gè)叫 full 的 variable,那我只要在 module 里寫:

          EXPORT_SYMBOL(full);

          就會(huì)自動(dòng)將 full export 出去,你馬上就可以從 ksyms 里發(fā)現(xiàn)有 full 這個(gè)變量被 export 出去。在使用 EXPORT_SYMBOL 之前,要小心一件事,就是必須在 gcc 里定義 EXPORT_SYMTAB 這個(gè) constant,否則在 compile 時(shí)會(huì)發(fā)生 parser error。所以,要使用 EXPORT_SYMBOL 的話,那 gcc 應(yīng)該要下:

          gcc -c -D__KERNEL__ -DMODULE -DMODVERSIONS -DEXPORT_SYMTAB
          main.c -include /usr/src/linux/include/linux/modversions.h

          如果我們不想 export 任何的東西,那我們只要在 module 里下

          EXPORT_NO_SYMBOLS;

          就可以了。使用 EXPORT_NO_SYMBOLS 用不著定義任何的 constant。其實(shí),如果各位使用過舊版的 register_symbol 的話,一定會(huì)覺得新版的方式比較好用。至少我是這樣覺得啦。因?yàn)槭褂?register_symbol 還要先定義出自己的 symbol_table,感覺有點(diǎn)麻煩。

          當(dāng)我們使用 EXPORT_SYMBOL 把一些 function 或 variable export 出來之后,我們使用 ksyma -a 去看一些結(jié)果。我們發(fā)現(xiàn) EXPORT_SYMBOL(full) 的確是把 full export出來了 :

          c8822200 full [my_module]
          c01b8e08 pci_find_slot_R454463b5
          . . .

          但是,結(jié)果怎幺跟我們想象中的不太一樣,照理說,應(yīng)該是 full_Rxxxxxx 之類的東西才對(duì)啊,怎幺才出現(xiàn) full 而已呢 ? 奇怪,問題在那里呢 ?

          其實(shí),問題就在于我們沒有對(duì)本身的 module 所 export 出來的 function 或 variable 的名字做 encode。想想,如果在 module 的開頭。我們加入一行

          #define full full_Rxxxxxx

          之后,我們?cè)僦匦?compile module 一次,載到 kernel 之后,就可以發(fā)現(xiàn) ksyms -a 顯示的是

          c8822200 full_Rxxxxxx [my_module]
          c01b8e08 pci_find_slot_R454463b5
          . . . . .

          了。那是不是說,我們要去對(duì)每一個(gè) export 出來的 variable 和 function 做 define 的動(dòng)作呢 ? 當(dāng)然不是啰。記得嗎,前頭我們講去使用 kernel export 的 function 時(shí),由于 include 了一些 .ver 的檔案,以致于我們不用再做 define 的動(dòng)作?,F(xiàn)在,我們也要利用 .ver 的檔案來幫我們,使我們 module export 出來的 function 也可以自動(dòng)加入 kernel version 的 information。也就是變成 full_Rxxxxxx 之類的東西。

          Linux 里提供了一個(gè) command,叫 genksyms,就是用來幫我們產(chǎn)生這種 .ver 的檔案的。它會(huì)從 stdin 里讀取 source code,然后檢查 source code 里是否有 export 的 variable 或 function。如果有,它就會(huì)自動(dòng)為每個(gè) export 出來的東西產(chǎn)生一些 define。這些 define 就是我們之前說的。等我們有了這些 define 之后,只要在我們的 module 里加入這些 define,那 export 出來的 function 或 variable 就會(huì)變成上面那個(gè)樣子。

          假設(shè)我們的程序都放在一個(gè)叫 main.c 的檔案里,我們可以使用下列的方式產(chǎn)生這些 define。

          gcc -E -D__GENKSYMS__ main.c | genksyms -k 2.2.1 >; main.ver

          gcc 的 -E 參數(shù)是指將 preprocessing 的結(jié)果 show 出來。也就是說將它 include 的檔案,一些 define 的結(jié)果都展開。-D__GENKSYMS__ 是一定要的。如果沒有定義這個(gè) constant,你將不會(huì)看到任何的結(jié)果。用一個(gè)管線是因?yàn)?genksyms 是從 stdin 讀資料的,所以,經(jīng)由管線將 gcc 的結(jié)果傳給 genksyms。-k 2.2.1 是指目前使用的 kernel 版本是 2.2.1,如果你的 kernel 版本不一樣,必須指定你的 kernel 的版本。產(chǎn)生的 define 將會(huì)被放到 main.ver 里。產(chǎn)生完 main.ver 檔之后,在 main.c 里將它 include 進(jìn)來,那一切就 OK 了。有件事要告訴各位的是,使用這個(gè)方式產(chǎn)生的 module,其 export 出來的東西會(huì)經(jīng)由 main.ver 的 define 改頭換面。所以如果你要讓別人使用,那你必須將 main.ver 公開,不然,別人就沒辦法使用你 export 出來的東西了。

          講了這幺多,相信各位應(yīng)該都已經(jīng)比較清楚 module 在 kernel 中是怎幺樣一回事,也應(yīng)該知道為什幺有時(shí)候 module 會(huì)無法加載了。除此之外,各位應(yīng)該還知道如何使自己 module export 出來的東西也具有 kernel version 的 information。

          接下來,要跟各位講的就是,如何寫一個(gè) module 了。其實(shí),寫一個(gè) module 很簡(jiǎn)單的。如果你了解我上面所說的東西。那我再講一次,再用個(gè)例子,相信大家就都會(huì)了。要寫一個(gè) module,必須要提供兩個(gè) function。這兩個(gè) function 是給 insmod 和 rmmod 使用的。它們分別是 init_module(),以及 cleanup_module()。

          int init_module();
          void cleanup_module();

          相信大家都知道在 Linux 里可以使用 insmod 這個(gè) command 來將某個(gè) module 加載。比方說,我有一個(gè) module 叫 hello.o,那使用 insmod hello.o 就可以將 hello 這個(gè) module 載到 kernel 里。觀察 /etc/modules 應(yīng)該就可以看到 hello 這個(gè) module 的名字。如果要將 hello 這個(gè) module 移除,則只要使用 rmmod hello 就可以了。insmod 在加載 module 之后,就會(huì)去呼叫 module 所提供的 init_module()。如果傳回 0 表示成功,那 module 就會(huì)被加載。如果失敗,那加載的動(dòng)作就會(huì)失敗。一般來講,我們?cè)?init_module() 做的事都是一些初始化的工作。比方說,你的 module 需要一塊內(nèi)存,那你就可以在 init_module() 做 kmalloc 的動(dòng)作。想當(dāng)然爾。cleanup_module() 就是在 module 要移除的時(shí)候做的事。做的事一般來講就是一些善后的工作,比方像把之前 kmalloc 的內(nèi)存 free 掉。

          由于 module 是載到 kernel 使用的,所以,可能別的 module 會(huì)使用你的 module,甚至某些 process 也會(huì)使用到你的 module,為了避免 module 還有人使用時(shí)就被移除,每個(gè) module 都有一個(gè) use count。用來記錄目前有多少個(gè) process 或 module 正在使用這個(gè) module。當(dāng) module 的 use count 不等于 0 時(shí),module 是不會(huì)被移除掉的。也就是說,當(dāng) module 的 use count 不等于 0 時(shí),cleanup_module() 是不會(huì)被呼叫的。

          在此,我要介紹三個(gè) macro,是跟 module 的 use count 有關(guān)的。

          MOD_INC_USE_COUNT
          MOD_DEC_USE_COUNT
          MOD_IN_USE

          MOD_INC_USE_COUNT 是用來增加 module 的 use count,而 MOD_DEC_USE_COUNT 是用來減少 module 的 use count。至于 MOD_IN_USE 則是用來檢查目前這個(gè) module 是不是被使用中。也就是檢查 use count 是否為 0。module 的 use count 必須由寫 module 的人自己來 maintain。系統(tǒng)并不會(huì)自動(dòng)為你把 use count 加一或減一。一切都得由自己控制。下面有一個(gè)例子,但是,并不會(huì)介紹這三個(gè) macro 的使用方法。將來如果有機(jī)會(huì),我再來介紹這三個(gè) macro 的用法。

          這個(gè)例子很簡(jiǎn)單。其實(shí)只是示范如何使用 init_module() 以及 cleanup_module() 來寫一個(gè) module。當(dāng)然,這兩個(gè) function 只是構(gòu)成 module 的基本條件罷了。至于 module 里要提供的功能則是看各人的需要。

          main.c
          #define MODULE
          #include linux/module.h>;
          #include asm/uaccess.h>;
          int full;
          EXPORT_SYMBOL(full); /* 將 full export 出去 */
          int init_module( void )
          {
          printk( 5>; Module is loadedn );
          return 0;
          }
          void cleanup_module( void )
          {
          printk( 5>; Module is unloadedn );
          }

          關(guān)于 printk 是這樣子的,它是 kernel 所提供的一個(gè)打印訊息的 function。kernel 有 export 這個(gè) function。所以你可以自由的使用它。它的用法跟 printf 幾乎一模一樣。唯獨(dú)訊息的開頭是 5>;,其實(shí),不見得這三個(gè)字符啦。也可以是 4>;,3>;,7>; 等等的東西。這是代表這個(gè)訊息的 prioirty 或 level。5>; 表示的是跟 KERNEL 有關(guān)的訊息。

          main.ver:

          利用 genksyms 產(chǎn)生出來的。

          gcc -E -D__GENKSYMS__ main.c | genksyms -k 2.2.1 >; main.ver

          接下來,就是要把 main.c compile 成 main.o

          gcc -D__KERNEL__ -DMODVERSIONS -DEXPORT_SYMTAB -c
          -I/usr/src/linux/include/linux -include
          /usr/src/linux/include/linux/modversions.h
          -include ./main.ver main.c

          好了。main.o 已經(jīng)成功的 compile 出來了,現(xiàn)在下一個(gè) command,

          insmod main.o

          檢查看 /proc/modules 里是否有 main 這個(gè) module。如果有,表示 main 這個(gè) module 已經(jīng)載到 kernel 了。再下一個(gè)指令,看看 full export 出去的結(jié)果。

          ksyms

          結(jié)果顯示

          Address Symbol Defined by
          c40220e0 full_R355b84b2 [main]
          c401d04c ne_probe [ne]
          c401a04c ei_open [8390]
          c401a094 ei_close [8390]
          c401a504 ei_interrupt [8390]
          c401af1c ethdev_init [8390]
          c401af80 NS8390_init [8390]

          可以看到 full_R355b84b2,表示,我們已經(jīng)成功的將 full 的名字加上 kernel version 的 information 了。當(dāng)我們不需要這個(gè) module 時(shí),我們就可以下一個(gè) command,

          rmmod main

          這樣 main 就會(huì)被移除掉了。再檢查看看 /proc/modules 就可以發(fā)現(xiàn) main 那一行不見了。各位現(xiàn)在可以看一下 /var/log/message 這個(gè)檔案,應(yīng)該可以發(fā)現(xiàn)以兩行

          Apr 12 14:19:05 host kernel: Module is loaded
          Apr 12 14:39:29 host kernel: Module is unloaded

          這兩行就是 printk 印出來的。

          關(guān)于 module 的介紹已經(jīng)到此告一段落了。其實(shí),使用 module 實(shí)在是很簡(jiǎn)單的一件事。對(duì)于要發(fā)展 driver 或是增加 kernel 某些新功能的人來講,用 module 不啻為一個(gè)方便的方式。希望這篇文章對(duì)各位能有所幫助。


          莊榮城 (J.C. Chuang), cjc86@cs.ccu.edu.tw
          linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)


          關(guān)鍵詞: 模塊 Linux 內(nèi)核編譯

          評(píng)論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉