?? (ldd) ch02-編寫和運行模塊(轉載).htm
字號:
color=#ffffff>關于</FONT></A></DIV></TD>
<TD width="1%" height=4>
<DIV align=center><FONT color=#ffffff>|</FONT></DIV></TD>
<TD width="8%" height=4>
<DIV align=center><A href="mailto:joyfire@sina.com"><FONT
color=#ffffff>聯系</FONT></A></DIV></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<TABLE borderColor=#666666 cellPadding=2 width="90%" align=center border=2>
<TBODY>
<TR>
<TD bgColor=#000000>
<P align=center><A
href="http://211.71.69.201/joyfire/lsdp/index.htm"><FONT color=#ffffff
size=2>目錄頁</FONT></A> | <A
href="http://211.71.69.201/joyfire/lsdp/3.htm"><FONT color=#ffffff
size=2>上一頁</FONT></A> | <A
href="http://211.71.69.201/joyfire/lsdp/5.htm"><FONT color=#ffffff
size=2>下一頁</FONT></A></P>
<P align=center><FONT face=黑體 color=#ffffff size=6>(LDD) Ch02-編寫和運行模塊(轉載)
</FONT></P><SPAN style="LINE-HEIGHT: 1; LETTER-SPACING: 0pt"><FONT
color=#ffffff size=3>
<P>發信人: Altmayer (alt), 信區: GNULinux<BR>標 題: (LDD) Ch02-編寫和運行模塊(轉載)<BR>發信站: 飲水思源 (2001年12月13日08:57:09 星期四), 站內信件<BR> <BR>【 以下文字轉載自 <FONT
color=#00ff00>UNIXpost </FONT>討論區 】<BR>【 原文由<FONT
color=#00ff00> altmayer.bbs@bbs.nju.edu.cn,</FONT> 所發表 】<BR> <BR>【 以下文字轉載自 <FONT
color=#00ff00>altmayer </FONT>的信箱 】<BR>第2章 編寫和運行模塊<BR> <BR> <BR>非常高興現在終于可以開始編程了。本章將介紹模塊編程和內核編程所需的所有必要的<BR>概念。我們將要不多的篇幅來編寫和運行一個完整的模塊。這種專業技術(expertise)<BR>是編寫如何模塊化設備驅動程序的基礎。為了避免一下子給你很多概念,本章僅介紹模<BR>塊,不介紹任何類別的設備。<BR> <BR>這里介紹的所有內核內容(函數,變量,頭文件和宏)也將在本章最后的參考部分再次<BR>介紹。<BR> <BR>如果你已經座不住了,下面的代碼是一個完整的“Hello, World”模塊(這個模塊事實<BR>上并沒什么功能)。它可以在Linux 2.0或以上版本上編譯通過,但不能低于或等于1.2<BR>,關于這一點本章將在稍后的部分解釋*。<BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>(代碼)<BR> <BR>函數printk是由Linux內核定義的,功能與printf相似;模塊可以調用printk,這是因為<BR>在insmod加載了模塊后,模塊就被連編到內核中了,也就可以調用內核的符號了。字符<BR>串<1>是消息的優先級。我之所以在模塊中使用了高優先級是因為,如果你使用的是內核<BR>2.0.x和舊的klogd守護進程,默認優先級的消息可能不能顯示在控制臺上(關于這個問<BR>題,你可以暫且忽略,我們將在第4章,“調試技術”,的“Printk”小節中詳細解釋)<BR>。<BR> <BR>通過執行insmod和rmmod命令,你可以試試這個模塊,其過程如下面的屏幕輸出所示。注<BR>意,只有超級用戶才能加載 托對嗇 塊。<BR> <BR>(代碼)<BR> <BR>正如你所見,編寫一個模塊很容易。通過本章我們將深入探討這個內容。<BR> <BR>模塊與應用程序<BR>在深入探討模塊之前,很有必要先看一看內核模塊與應用程序之間的區別。<BR> <BR>一個應用從頭到尾完成一個任務,而模塊則是為以后處理某些請求而注冊自己,完成這<BR>個任務后它的“主”函數就立即中止了。換句話說就是,init_module()(模塊的入口點<BR>)的任務就是為以后調用模塊的函數做準備;這就好比模塊在說,“我在這,這是我能<BR></P></FONT><FONT
color=#ffffff size=3>
<P>)的任務就是為以后調用模塊的函數做準備;這就好比模塊在說,“我在這,這是我能<BR>做的?!蹦K的第二個入口點,cleanup_module,僅當模塊被下載前才被調用。它應該<BR>跟內核說,“我不在這了,別再讓我做任何事了?!蹦軌蛐遁d也許是你最喜愛的模塊化<BR>的特性之一,它可以讓你減少開發時間;你無需每次都花很長的時間開機關機就可以測<BR>試你的設備驅動程序。<BR> <BR>作為一個程序員,你一定知道一個應用程序可以調用應用程序本身沒有定義的函數:前<BR>后的連編過程可以用相應的函數庫解析那些外部引用。printf就是這樣一個函數,它定<BR>義在libc中。然而,內核要僅能連編到內核中,它能調用的僅是由內核開放出來的那些<BR>函數。例如,上面的helllo.c中的printk函數就是內核版的printf,并由內核開放給模<BR>塊給使用;除了沒有浮點支持外,它和原函數幾乎一模一樣。<BR> <BR>如圖2-1所示,它勾畫了為了在運行的內核中加入新函數,是如何調用函數以及如何使用<BR>函數指針的。<BR> <BR>由于沒有庫連接到模塊中,源碼文件不應該模塊任何常規頭文件。與內核有關的所有內<BR>容都定義在目錄/usr/include/linux和/usr/include/asm下的頭文件中。在編譯應用程<BR>序也會間接使用這些頭文件;其中的內核代碼通過#ifdef __KERNEL__保護起來。這兩個<BR>內核頭文件目錄通常都是到內核源碼所在位置的符號連接。如果你根本就想要整個內核<BR>源碼,你至少還要這兩個目錄的頭文件。在比較新的內核中,你還可以在內核源碼中發<BR>現net和scsi頭文件目錄,但很少有模塊會需要這兩個目錄。<BR> <BR>內核頭文件的作用將稍后需要它們的地方再做介紹,<BR></P></FONT><FONT
color=#ffffff size=3>
<P>內核頭文件的作用將稍后需要它們的地方再做介紹,<BR> <BR>內核模塊與應用程序的另一個區別是,你得小心“名字空間污染”問題。程序員在寫小<BR>程序時,往往不注意程序的名字空間,但當這些小程序成為大程序的一部分時就會造成<BR>許多問題了。名字空間污染是指當存在很多函數和全局變量時,它們的名字已不再富有<BR>足夠的意義來很容易的區分彼此的問題。不得不處理這種應用程序的程序員必須花很大<BR>的精力來單單記住這些“保留”名,并為新符號尋找新的唯一的名字。如果在寫內核代<BR>碼時出現這樣的錯誤,這對我們來說是無法忍受的,因為即便最小的模塊也要連編到整<BR>個內核中。防止名字空間污染的最佳方法是把所有你自己的符號都聲明為static的,而<BR>且給所有的全局量加一個well-defined前綴。此外,你還可以通過聲明一個符號表來避<BR>免使用static聲明,這些內容將在本章的“注冊符號表”小節中介紹。即便是模塊內的<BR>私有符號也最好使用選定的前綴,這樣有時會減輕調試的工作。通常,內核中使用的前<BR>綴都是小寫的,今后我們將貫徹這一約定。<BR> <BR>內核編程和應用程序編程的最后一個區別是如何處理失效:在應用程序開發期間,段違<BR>例是無害的,利用調試器可以輕松地跟蹤到引起問題的錯誤之處,然而內核失效卻是致<BR>命的,如果不是整個系統,至少對于當前進程是這樣的。我們將在第4章“調試系統失效<BR>”小節中介紹如何跟蹤內核錯誤。<BR> <BR>用戶空間和內核空間<BR>本節的討論概而言之就是,模塊是在所謂的“內核空間”中運行的,而應用程序則是在<BR>“用戶空間”中運行的。這些都是操作系統理論的最基本概念。<BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>事實上,操作系統的作用就是給程序提供一個計算機硬件的一致的視圖。此外,操作系<BR>統處理程序的獨立操作,并防止對資源的未經授權的訪問。當且僅當CPU可以實現防止系<BR>統軟件免受應用軟件干擾的保護機制,這些不同尋常的工作才有可能實現。<BR> <BR>每種現代處理器都能實現這種功能。人們選擇的方案是在CPU內部實現不同的操作模式(<BR>或級)。不同的級有不同的作用,而且某些操作不允許在最低級使用;程序代碼僅能通<BR>過有限數目的“門”從一個級切換到另一個級。Unix系統就是充分利用這一硬件特性設<BR>計而成的,但它只使用了兩級(與此不同,例如,Intel處理器就有四級)。在Unix系統<BR>中,內核在最高級執行(也稱為“管理員態”),在這一級任何操作就可以,而應用程<BR>序則執行在最低級(所謂的“用戶態”),在這一級處理器禁止對硬件的直接訪問和對<BR>內存的未授權訪問。<BR> <BR>正如前面所述,在談到軟件時,我們通常稱執行態為“內核空間”和“用戶空間”,它<BR>們分別引用不同的內存映射,也就是程序代碼使用不同的“地址空間”。<BR> <BR>Unix通過系統調用和硬件中斷完成從用戶空間到內核空間的控制轉移。執行系統調用的<BR>內核代碼在進程的上下文上執行――它代表調用進程操作而且可以訪問進程地址空間的<BR>數據。但與此不同,處理中斷的代碼相對進程而言是異步的,而且與任何一個進程都無<BR>關。<BR> <BR>模塊的功能就是擴展內核的功能;運行在內核中的模塊化的代碼。通常,一個設備驅動<BR>程序完成上面概括的兩個任務:模塊的某些函數做為系統調用執行,而某些函數則負責<BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>事實上,操作系統的作用就是給程序提供一個計算機硬件的一致的視圖。此外,操作系<BR>統處理程序的獨立操作,并防止對資源的未經授權的訪問。當且僅當CPU可以實現防止系<BR>統軟件免受應用軟件干擾的保護機制,這些不同尋常的工作才有可能實現。<BR> <BR>每種現代處理器都能實現這種功能。人們選擇的方案是在CPU內部實現不同的操作模式(<BR>或級)。不同的級有不同的作用,而且某些操作不允許在最低級使用;程序代碼僅能通<BR>過有限數目的“門”從一個級切換到另一個級。Unix系統就是充分利用這一硬件特性設<BR>計而成的,但它只使用了兩級(與此不同,例如,Intel處理器就有四級)。在Unix系統<BR>中,內核在最高級執行(也稱為“管理員態”),在這一級任何操作就可以,而應用程<BR>序則執行在最低級(所謂的“用戶態”),在這一級處理器禁止對硬件的直接訪問和對<BR>內存的未授權訪問。<BR> <BR>正如前面所述,在談到軟件時,我們通常稱執行態為“內核空間”和“用戶空間”,它<BR>們分別引用不同的內存映射,也就是程序代碼使用不同的“地址空間”。<BR> <BR>Unix通過系統調用和硬件中斷完成從用戶空間到內核空間的控制轉移。執行系統調用的<BR>內核代碼在進程的上下文上執行――它代表調用進程操作而且可以訪問進程地址空間的<BR>數據。但與此不同,處理中斷的代碼相對進程而言是異步的,而且與任何一個進程都無<BR>關。<BR> <BR>模塊的功能就是擴展內核的功能;運行在內核中的模塊化的代碼。通常,一個設備驅動<BR>程序完成上面概括的兩個任務:模塊的某些函數做為系統調用執行,而某些函數則負責<BR></P></FONT><FONT
color=#ffffff size=3>
<P>程序完成上面概括的兩個任務:模塊的某些函數做為系統調用執行,而某些函數則負責<BR>處理中斷。<BR> <BR>內核中的并發<BR>內核編程新手首先要問的問題之一就是多任務是如何管理的。事實上,除了調度器之外<BR>,關于多任務并沒有什么可以多說的,而且調度器也超出了程序員的一般活動范圍。你<BR>可能會遇到這些任務,除了掌握如下這些原則外,模塊編寫者無需了解多任務。<BR> <BR>與串行的應用程序不同,內核是異步工作的,代表進程執行系統調用。內核負責輸入/輸<BR>出以及系統內對每一個進程的資源管理。<BR> <BR>內核(和模塊)函數完全在一個線程中執行,除非它們要“睡眠”,否則通常都是在單<BR>個進程的上下文中執行――設備驅動程序應該能夠通過交織不同任務的執行來支持并發<BR>。例如,設備可能由兩個不同的進程同時讀取。設備驅動程序串行地響應若干read調用<BR>,每一個都屬于不同的進程。由于代碼需要區別不同的數據流,內核(以及設備驅動程<BR>序)必須維護內部數據結構以區分不同的操作。這與一個學生學習交織在一起的若干門<BR>課程并非不無相似之處:每門課都有一個不同的筆記本。解決多個訪問問題的另一個方<BR>法就是避免它,禁止對設備的并發訪問,但這種怠惰的技術根本不值的討論。<BR> <BR>當內核代碼運行時,上下文切換不可能無意間發生,所以設備驅動程序無需是可重入的<BR>,除非它自己會調用schedule。必須等待數據的函數可以調用sleep_on,這個函數接著<BR>又調用schedule。不過你必須要小心,存在某些函數會無意導致睡眠,特別是任何對用<BR>戶空間的訪問。利用“天然非搶占”特性不是什么好的方法。我將在第5章,“字符設備<BR></P></FONT><FONT
color=#ffffff size=3>
<P>戶空間的訪問。利用“天然非搶占”特性不是什么好的方法。我將在第5章,“字符設備<BR>驅動程序的擴展操作”的“編寫可重入代碼”小節中講解可重入函數。<BR> <BR>就對設備驅動程序的多個訪問而言,有許多不同的途徑來分離這些不同的訪問,但都是<BR>依賴于任務相關的數據。這種數據可以是全局內核變量或是傳給設備驅動程序函數的進<BR>程相關參數。最重要的用來跟蹤進程的全局變量是current:一個指向struct<BR>task_struct結構的指針,在<linux/sched.h>中定義。current指針指向當前正在運行的<BR>用戶進程。在系統調用執行期間,如open或read,當前進程就是調用這個調用的進程*。<BR>如果需要的話,內核代碼就可以利用current使用進程相關信息。第5章“設備文件的訪<BR>問控制”小節中就有使用這種技術的例子。<BR> <BR>編譯器就象外部引用printk一樣處理current。模塊可以在任何需要的地方引用current<BR>,insmod會在加載時解析出所有對它的引用。例如,如下語句通過訪問struct<BR>task_struct中的某些域打印當前進程的進程ID和命令名:<BR> <BR>(代碼)<BR> <BR>存儲在current->comm中的命令名是當前進程最后執行的可執行文件的基名。<BR> <BR>編譯和加載<BR>本章的剩下部分將介紹編寫雖然是無類別但很完整的模塊。就是說,模塊不屬于任何第1<BR>章“設備和模塊的類別”中羅列的類別中的任何一個。本章中出現的設備驅動程序稱為s<BR>kull,是“Simple Kernel Utility for Loading Localities”的縮寫。去掉這個模塊<BR></P></FONT><FONT
color=#ffffff size=3>
<P>kull,是“Simple Kernel Utility for Loading Localities”的縮寫。去掉這個模塊<BR>提供的范例函數,你可以重用這個模塊,向內核加載你自己的本地代碼。*<BR> <BR>在我們介紹init_module和cleanup_module的作用之前,首先讓我們寫一個Makefile來編<BR>譯內核可以加載的目標代碼。<BR> <BR>首先,在包含任何頭文件前,我們需要在預處理器中定義符號__KERNEL__。這個符號用<BR>于選擇使用頭文件的哪一部分。由于libc包含了這些頭文件*,應用程序最終也會包含內<BR>核頭文件,但應用程序不需要內核原型。于是就用__KERNEL__符號和#ifdef將那些額外<BR>的去掉。將內核符號和宏開放給用戶空間的程序會造成那個程序的名字空間污染。如果<BR>你正在為一臺SMP(對稱多處理器)機器編譯,你還需要在包含內核頭文件前定義__SMP_<BR>_。這一要求似乎有點不那么方便,但一旦開放人員找到達成SMP透明的正確方法,它就<BR>會逐漸消失的。<BR> <BR>另一個很重要的符號就是MODULE,必須在包含<linux/module.h>前定義這個符號。除非<BR>要把設備驅動程序編譯到內核映象中去,MODULE應該總是定義了的。由于本書所涉及的<BR>驅動程序都不是直接連編到內核中去的,它們都定義了這個符號。<BR> <BR>由于頭文件中的函數都是聲明為inline的,模塊編寫者還必須給編譯器指定-O選項。gcc<BR>只有打開優化選項后才能擴展內嵌函數,不過它能同時接受-g和-O選項,這樣你就可以<BR>調試那些內嵌函數的代碼了*。<BR> <BR>最后,為了防止發生令人不愉快的錯誤,我建議你使用-Wall(全面報警)編譯選項,并<BR></P></FONT><FONT
color=#ffffff size=3>
<P>最后,為了防止發生令人不愉快的錯誤,我建議你使用-Wall(全面報警)編譯選項,并<BR>且還要修改源碼去除所有編譯器給出的警告,即便這樣做會改變你已有的編程風格,你<BR>也要這么做。<BR> <BR>所有我目前介紹的定義和選項都在make使用的CFLAGS變量中。<BR> <BR>除了一個合適的CFLAGS變量外,將要編寫的Makefile還需要一個將不同目標文件連接在<BR>一起的規則。這條規則僅當一個模塊被分成若干個不同的源文件時才需要,這種并非很<BR>不常見。通過命令ld -r將模塊連接在一起,這條命令雖然調用了連接器,但并沒有連編<BR>操作。這是因為輸出還是一個目標文件,它是輸入文件的混合。-r選項的意思是“可重<BR>定位”; 輸出文件是可重定位的,這是因為它尚未嵌入絕對地址。<BR> <BR>下面的Makefile實現了上述的所有功能,它能建立由兩個源文件組成的模塊。如果你的<BR>模塊是由一個源文件組成的,只要跳過包含ld -r的那項就可以了。<BR> <BR>(代碼)<BR> <BR>上面文件中那個復雜的install規則將模塊安裝到一個版本相關的目錄中,稍后將做解釋<BR>。Makefile中的變量VER是從<linux/version.h>中截取的版本號。<BR> <BR>模塊編好了,接下來必須把它加載到內核中。正如我前面所說,insmod就是完成這個工<BR>作的。這個程序有點象ld,它要將模塊中未解析的符號連編到正在運行的內核的符號表<BR>中。但與連接器不同,它并不修改磁盤文件,而是修改內存映象。insmod有很多命令選<BR></P></FONT><FONT
color=#ffffff size=3>
<P>中。但與連接器不同,它并不修改磁盤文件,而是修改內存映象。insmod有很多命令選<BR>項(如果想知道細節,可以看man),可以在模塊連編到內核前修改模塊中的整數值和字<BR>符串值。因此,如果一個模塊設計得體,可以在加載時對其進行配置;加載時配置要比<BR>編譯時配置更靈活,但不幸的是,有時候仍然有人使用后者。加載時配置將在本章的后<BR>面“自動和手動配置”小節中講解。<BR> <BR>感興趣的讀者可能想知道內核是怎樣支持insmod的:它依賴于kernel/modulec.c中定義<BR>的幾個系統調用。sys_create_module為裝載模塊分配內存(這些內存是由vmalloc分配<BR>的,見第7章“獲取內存”中的“vmalloc及其同胞”一節),為了連編模塊,系統調用g<BR>et_kernel_syms返回內核符號表,sys_init_module將可重定位目標碼復制到內核空間并<BR>調用模塊的初始化函數。<BR> <BR>如果你看過了內核源碼,你就會發現系統調用的名字都有sys_前綴。所有系統調用都是<BR>這樣,其他函數并沒有這個約定;當你在源碼中查找系統調用時,知道這一點會對你有<BR>所幫助。<BR> <BR>版本相關性<BR>要時刻牢記,對于你想連編的每一個不同版本的內核,你的模塊都要相應地編譯一次。<BR>每個模塊都定義了一個稱為kernel_version的符號,insmod檢查這個符號是否與當前內<BR>核版本號匹配。較新的內核已在<linux/module.h>中替你定義了這個符號(這也就是為<BR>什么hello.c中沒有對它的聲明)。這也意味著,如果你的模塊是由多個源文件組成的,<BR>你只能有一個源文件包含了<linux/module.h>。與此相反,當你在Linux 1.2下編譯時,<BR>必須在你的源碼中定義kernel_version。<BR></P></FONT><FONT
color=#ffffff size=3>
<P>必須在你的源碼中定義kernel_version。<BR> <BR>如果版本不匹配,而你仍然想在不同版本的內核里加載你的模塊,可以在insmod命令中<BR>指定-f(“強制”)選項完成,但這個操作不安全,可能會失敗。而且很難事先說明要<BR>發生那種情況。由于符號不匹配,加載就會失敗,此時你會得到一個錯誤信息。內核內<BR>部的變化也會造成加載失敗。如何這種情況發生了,你可能會在系統運行時得到一個非<BR>常嚴重的錯誤,很可能造成系統panic――出于這個緣由,注意版本失配。事實上,通過<BR>內核里的“版本機制”更完美地解決版本失配問題(稍后,第11章“Kerneld和高級模塊<BR>化”的“模塊內版本控制”小節將介紹這一更先進的內容)。<BR> <BR>如果你需要為某個特定的內核編譯模塊,你必須在上面的Makefile中包含相應內核的頭<BR>文件(例如,通過聲明不同的INCLUDEPATH)。<BR> <BR>為了處理加載時的版本相關性,insmod安裝特定的路徑查詢:如果不能在當前目錄找到<BR>模塊,就在版本相關的目錄中查找,如果還失敗就在/lib/modules/misc中查找。上面那<BR>個Makefile中的install規則就遵循了這一約定。<BR> <BR>寫一個可以在從1.2.13到2.0.x的任一版本的內核上編譯的內核是件復雜的任務。模塊化<BR>接口已經做了修改,配置越來越容易。你可以看到上面的那個hello.c中,只要你只處理<BR>較新的內核就什么都不用聲明。與此不同,可移植的接口如下所示:<BR> <BR>(代碼)<BR> <BR></P></FONT><FONT
color=#ffffff size=3>
<P><BR>在2.0或更新的內核中,module.h包含了version.h,而且,如果沒有定義__NO_VERSION_<BR>_,module.h還定義了kernel_version。<BR> <BR>如果你需要將多個源文件連接在一起組成一個模塊,而又有多個文件都需要包含<linux/<BR>module.h>――比如你需要module.h里聲明的宏,就可以使用符號__NO_VERSION__。在包<BR>含module.h前定義__NO_VERSION__就可以在你不想要自動聲明字符串kernerl_version的<BR>源文件里防止它的發生(ld -r會對一個符號的多處定義報警)。本書中的模塊就使用__<BR>NO_VERSION__達成這一目的。<BR> <BR>其他基于內核版本的相關性可以通過預處理的條件編譯解決――version.h定義了整數宏<BR>LINUX_VERSION_CODE。這個宏展開后是內核版本的二進制表示,一個字節代表版本發行<BR>號的一部分。例如,1.3.5的編碼是66309(即,0x10305)。*利用這個信息,你可以輕<BR>松地判斷你正處理的是哪個版本的內核。<BR> <BR>當你檢查某個版本時,使用十進制表示是不方便的。為了在一個源文件里支持多個內核<BR>版本,我將用下面的宏通過版本號的3個部分構建版本編碼:<BR> <BR>(代碼)<BR> <BR>內核符號表<BR>我們已經知道insmod是如何利用公開內核符號來解析未定義符號的了。這張表包含了實<BR>現模塊化設備驅動程序所需的全局內核 瞑D―函數和變量??梢詮奈募?proc/ksyms中以<BR></P></FONT><FONT
color=#ffffff size=3>
<P>現模塊化設備驅動程序所需的全局內核 瞑D―函數和變量??梢詮奈募?proc/ksyms中以<BR>文本的方式讀取這個公開符號表<BR> <BR>當你的模塊被加載時,你聲明的任何全局符號都成為內核符號表的一部分,你可以從文<BR>件/proc/ksyms或命令ksyms的結果了解這一點。<BR> <BR>新模塊可以使用你開放出來的符號,而且你在其他模塊之上堆疊新模塊。在主流的內核<BR>源碼中也使用了這種模塊堆疊的方法:msdos文件系統依賴于fat模塊開放出來的符號,<BR>而ppp驅動程序則堆疊在報頭壓縮模塊上。<BR> <BR>在處理復雜對象時,模塊堆疊非常有用。如果以設備驅動程序的形式實現一個新的抽象<BR>,它可以提供一個設備相關的插接口。比如,幀緩沖視頻驅動程序可以將符號開放給下<BR>層VGA驅動程序使用。每個用戶都加載幀緩沖視頻驅動程序,然后在根據自己安裝的設備<BR>加載相應的VGA模塊。<BR> <BR>分層次的模塊化簡化了每一層的任務,大大縮減了開發時間。這同我們第1章中討論的機<BR>制與策略分離很相似。<BR> <BR>注冊符號表<BR>另一種開放你的模塊中的全局符號的方法是使用函數register_symtab,這個函數是符號<BR>表管理的正式接口。這里所涉及的編程接口適用于內核1.2.13和2.0。如果想詳細了解2.<BR>1開發用內核所做的變動,請參見第17章“最新發展”。<BR> <BR></P></FONT><FONT
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -