編寫適用於模擬器的 Linux 程式碼(轉)

ba發表於2007-08-11
編寫適用於模擬器的 Linux 程式碼(轉)[@more@]在某臺計算機上模擬其他計算機的歷史已經很長,通常是為了使用遺留應用程式,或者是為了使用為更穩定、響應更快的 OS 的系統上執行流行的 OS 而編寫的應用程式。隨著 Linux? 越來越流行,當開發人員規劃將執行於非 Linux 系統上的二進位制程式時,需要審視他們的選擇。本文將研究模擬器的功能,並將詳細地研究硬體模擬和軟體模擬的問題。

  在某臺計算機上模擬其他計算機已有多年的歷史。模擬老的計算機的一個常見原因是懷舊,不過不可否認,很多模擬器能夠非常出色地執行多種計算機遊戲。模擬其他計算機的另一個原因是為了使用只存在於某個特定平臺上的應用程式軟體。

  通常,應用程式模擬以佔據較大市場份額的平臺為目標。例如,WINE 專案嘗試去提供一個執行 Windows? 二進位制程式的途徑,因為 —— 面對現實吧 —— Windows 上的優秀應用程式比 Linux 上的多得多(儘管正如他們所指出的那樣,WINE 不是模擬器(WINE Is Not an Emulator))。

  不過,近年來 Linux 已經被證明是一個穩定而且全能的作業系統;因而,它的市場份額也有所增長。市場份額的增長激起了人們對模擬 Linux 的興趣。本文評論了在其他系統上進行 Linux 二進位制程式模擬的現狀,並著重指出為了讓人們更方便地在模擬環境中執行他們的二進位制程式,開發人員應該緊記的一些問題。

  基本的模擬器

  模擬器的思想很簡單。計算機是充分可預測的。如果您想確切地瞭解如果給出一段特定的程式碼計算機會做什麼,那麼透過建立這臺計算機的模型就可以得到結果。當然,這會涉及到相當多的開銷,但是,如果要模擬的計算機比正在進行模擬的計算機老得多,那麼模擬環境將比原來的機器更快。

  有一些模擬層,比如 NetBSD 的 Linux 模擬層,只是提供某個環境的軟體部分的模擬,從 Linux 程式庫取得系統呼叫,並處理返回結果,使得看起來像是在使用 Linux 核心。其他的模擬層,比如 VirtualPC,可以模擬整臺計算機,包括處理器。模擬處理器的速度會更慢,但是可以帶來更好的相容性。

  發行版本格式的模擬器

  儘管本文重點關注的是在其他平臺上執行 Linux 二進位制程式的方法,但是,經過編譯的二進位制程式發行版本同樣佔有一席之地。隨著 Linux 模擬環境越來越普及,Linux 二進位制程式格式成為發行簡單程式(不給出原始碼)的一個可行方法。Linux 二進位制程式可以在多種系統上執行,無可否認,有時需要付出一些代價 —— 以 Linux 二進位制程式格式作為通用發行版本格式還會遇到一些挑戰。

  通常,模擬不足以讓您在為另一個系統構建的程式中執行為某個系統構建的共享物件。如果您的產品大部分是以共享程式庫物件的形式發行的,那麼這些產品可能不會被載入到其他平臺上。

  有人認為,使用 Linux 二進位制程式格式來向其他平臺發行程式碼是瘋狂的。也許這很瘋狂,但它是可行的。近幾年,我的主要的 Web 瀏覽器就一直在模擬環境中執行(更不用提字處理器、文件轉換器,甚至信用卡處理軟體)。

  我們樂於使用的大部分軟體應用程式都是商用的,並且,能夠發行可以執行在很多平臺之上的單一的二進位制程式會使商業軟體供應商大大受益。如果有多種多樣的 Linux 模擬環境可用,那麼 Linux 二進位制程式格式會表現為第一個真正的軟體發行版本選擇。

  噢,移植原始碼是與發行有很大區別的任務;通常,移植任務更為簡單。

  完全硬體模擬器

  完全硬體模擬器會模擬一臺完整的機器;不只是處理器,還包括機器所有其餘部分。例如,被模擬的計算機可能擁有自己的鍵盤控制器和影片卡。

  完全硬體模擬常用於使用較老機器的程式。MAME 街機遊戲(arcade game)模擬器就是一個流行的示例,它模擬了多種老式街機遊戲機的硬體。

  就某些方面而言,完全硬體模擬器是進行模擬的最簡單方式。很多工作都需要構建一個完全硬體模擬器,但是一旦您擁有這樣一個模擬器,所有的事情就都可以迎刃而解。例如,用於 Macintosh 的 VirtualPC 版本 3 開始支援 Linux。

  硬體模擬可以解決使用其他方式難以解決的問題。例如,我以前有一個 BIOS 快閃記憶體工具,僅以用於 DOS 的自解壓縮的映像檔案的格式釋出。更糟糕的是,執行它的機器必須在傳統的 ISA 軟盤控制器上安裝實際的軟盤(我的 Windows 桌面機有一個 LS-120 驅動器)。透過模擬來解決這個問題吧!我在模擬器下執行該程式,將資料寫入已經插入 Mac 的一個 USB 軟盤驅動器。

  硬體模擬也有其不利方面。為了讓一切都能夠運轉,需要付出很大努力。如果需要網路,那麼還需要很好地模擬網路晶片,以使得作業系統可以在這個晶片上執行。此外,模擬本身所沒有的指令的代價可能非常高昂。通常,像這樣一個系統可以近乎完美地運轉,但是,與時限(timing)相關的功能可能會不可靠。

  完全硬體模擬器已經使用了很長時間,最適合處理速度可能受模擬影響的遺留系統和程式碼。

  雖然如此,想要在 Macintosh 或者任何其他非 x-86 機器上執行 x86 Linux 二進位制程式的使用者,為了嘗試執行程式,可能要完全依賴於某種當前可用的 x86 模擬器。在類似這樣的系統上,大部分工具程式將執行得非常好(雖然可能較慢)。要擔心的惟一一個主要顧慮是,為了提高效能,這種系統的使用者可能安裝較小的或者較老的 Linux 發行版本。使用 32 MB 記憶體來執行模擬機器的那些人不可能執行最新版本的 KDE。

  部分硬體模擬器

  部分硬體模擬器是一箇中間解決方案:它們模擬一臺計算機,但是這臺計算機只能是與它們實際上所在的計算機型別相同的計算機。由於執行的速度與宿主機器相當,所以類似這樣的程式可以降低模擬的成本。此類模擬器的示例包括 Serenity Virtual Station 和 VMWare。

  當您擁有用於多種作業系統的應用程式,而且需要同時執行它們時,這些系統最為實用。類似於完全硬體模擬,這樣的系統將執行一個完全的 Linux OS 環境,只要您的程式能夠適當地跨 Linux 系統移植,那麼就沒什麼問題。不過,再次宣告,Linux 的移植到較老版本的可移植性將有非常有用。使用虛擬機器的人們可能願意在這樣的系統上執行一個較老的、佔空間較小的 Linux 版本。

  軟體模擬器

  在模擬世界中,軟體模擬器是最基本的。軟體模擬器不在某臺虛擬機器上執行您的應用程式 —— 它不透過虛擬機器,而是實時地去執行它。建立一個環境,在這個環境中,程式的程式碼可以正常執行,但是,程式訪問作業系統的嘗試會被透過某個模擬層來傳送,這樣,這些程式就可以使用了。WINE 是一個極好的示例(雖然是用於 Windows),儘管它並不是一個正式的模擬器。

  有一些軟體模擬器是由使用者顯式地呼叫,比如可用於 SCO 和 Solaris 系統的 lxrun 程式。有些軟體模擬器則構建成為 UNIX? 核心對載入二進位制映像的支援 —— 如果程式看起來不正確,那麼,可以將它與一個可能模擬器表相對照,以檢視它們是否可以執行它。

  軟體模擬器通常會帶來最好的使用者體驗。不需要特殊的設定,不需要龐大的磁碟映像。程式只需要去執行即可(大部分情況下)。不過,訪問系統呼叫、共享程式庫以及檔案系統結構會引發許多問題,所以,接下來我們將討論它們。

  系統呼叫

  系統呼叫是模擬中最簡單也是最困難的部分。系統呼叫具有明確定義的介面,而且,通常可以方便地檢測並處理呼叫機制 —— 這是簡單的部分。困難之處在於可能難以或者不可能較好地實現系統呼叫。

  傳統上,Linux 模擬中最難以處理的是 clone() 系統呼叫。這個呼叫提供了獲得簡單執行緒的一個強制方法,即建立兩個共享許多內容程式,共享的內容可以包括記憶體、檔案描述符、訊號處理 —— 換句話說,可以包括任何內容和所有內容。不幸的是,如果您的作業系統不具備與此完全類似的功能,那麼沒有任何辦法來實現這個系統呼叫。

  更糟糕的是,由於當 POSIX 執行緒還沒有完善或獲得廣泛支援之前,clone() 就已經出現,並經常被用作 POSIX 執行緒的替代,所以,許多程式都以多種令人興奮的、複雜的且(我必須要說)意想不到的方式來使用它。

  如果您想讓人們執行您的二進位制程式,那麼嘗試讓他們不要使用針對特定作業系統的系統呼叫;最好使用標準的 POSIX 系統呼叫。這是軟體開發的一個良好的習慣做法。

  基於核心的模擬器可以捕捉到到達它的系統呼叫。使用者空間模擬器,比如 lxrun,會等待應用程式嘗試進行系統呼叫。由於 Linux 系統呼叫功能與 Solaris 或 SCO UNIX 上的系統呼叫功能不同,所以結果是發生一個程式碼段錯誤。然後,lxrun 程式像一個偵錯程式那樣糾正這個錯誤並使系統呼叫繼續執行 —— 但是,實際上,它已經擷取了這個系統呼叫,並向底層作業系統進行相應的系統呼叫,而且解決了所有問題。聰明!

  檔案系統結構

  檔案系統的問題通常更為微妙。訪問檔案系統極其簡單。不簡單的是如何找到您想要的檔案。

  如果您的程式在模擬環境中執行,那麼要訪問的檔案系統可能與您開發程式時使用的檔案系統有本質上的不同。例如,如果您的程式使用了 /proc 檔案系統(常用來獲得核心狀態和資訊),那麼在較新的核心中常見的特性在較老的系統中可能並不存在。

  這裡的開發人員比專有系統上的開發人員擁有巨大的優勢,因為不同的 Linux 發行版本以不同方式安排檔案,所以大部分程式設計師都非常清楚如何避免過分依賴於檔案系統設計。但是 —— 有時 —— 不得不將檔名嵌入到程式之中。

  許多模擬器解決這個難題所採取的一個方案是:建立一個針對檔案系統呼叫的額外的解釋層。例如,在 NetBSD 的 Linux 模擬環境程式碼中,首先根據 /emul/linux 中的檔案檢查對檔案的訪問,之後才對系統真正的 root 目錄中的檔案進行檢查。這就使得當 Linux 二進位制程式不能使用標準檔案時,系統可以提供“覆蓋(override)”系統檔案的檔案。

  實際上,這一方法的主要用途在於程式庫和其他支援檔案,不過也同樣提供了許多系統二進位制程式。例如,如果 Linux 二進位制程式嘗試呼叫 uname 來得到核心版本,卻得到了 NetBSD 的版本號,這將非常令人迷惑。取而代之,它應得到所預期的 Linux 版本號。

  共享程式庫

  如前所述,共享程式庫是能夠被模擬的二進位制程式找到卻不能夠被系統二進位制程式找到的一個非常好的例子。由於在不同的系統上共享程式庫的格式和 ABI 細節可能各異,所以不能隨意假定所有的系統都可以共享某個給定的程式庫。名稱可能衝突 —— 例如,當前 NetBSD 和 SUSE 7.3 都擁有一個名為 libncurses.so.5 的檔案。重要的是要使用其中正確的那一個。

  共享程式庫為開發人員指出了另外一個注意事項。瞭解不同的系統正在使用的程式庫版本很重要。現在,NetBSD 的 Linux 模擬環境正在使用的是 SUSE 7.3 共享程式庫。仍然有使用 9.1 共享程式庫的程式碼,但是它們會獲得警告,告之它們不能穩定地進行核心級模擬。

  模擬環境軟體包通常遠遠跟不上市場的步伐。即使您覺得大部分預期使用者都應該擁有了相當新的 Linux 發行版本,但是大批模擬器還是幾乎全都有些跟不上時代。

  共享程式庫還引發了另一個顧慮 —— 不是每個系統都包含全部共享程式庫。模擬環境軟體包通常不會安裝所有最新的共享程式庫。而且,更麻煩的是,它們的使用者也不太可能有能力輕鬆地安裝所缺少的軟體包。

  在這些情況下,最大限度地減少對新特性和非核心共享程式庫的依賴是一個好辦法。模擬器使用者可能會遇到這些問題。

  不要誤以為使用靜態程式庫就可以保證解決這些問題。靜態程式庫可能引入其自己的新的依賴,而且不容易檢查到它們。如果靜態地連結了一個使用某個不可移植的系統呼叫,那麼透過重寫演算法來避免這個系統呼叫將沒有什麼用處。動態連結讓您構建的程式能夠在更大範圍內的系統上執行。

  呼叫其他程式的程式

  有一種特別的情形比任何其他情形更令人們頭疼,尤其與安裝器相關。在很多系統上,呼叫 /bin/sh 所得到的 shell 不是bash。這就意味著使用 bash 擴充套件的指令碼可能不能在其他系統上執行。

  這就陷入了模擬器中的一個特別錯綜複雜的邏輯中。當執行二進位制程式時,作業系統可能知道的足夠多,可以核對相關的 Linux 二進位制程式的 Linux 路徑,而且它可能在那裡安裝 bash 的一個副本。但是,當您執行一個指令碼時,核心不會將其看作是一個 Linux 二進位制程式;它發現指令碼附帶有一個解釋程式路徑,當嘗試載入解釋程式時,它將不再執行於模擬模式之下。

  可移植 shell 指令碼技術在這裡得到了應用。當使用者執行被模擬的應用程式時,這是要面對的最常見問題之一。安裝器可能會因為不是可移植的 shell 指令碼而不能執行。

  類似於標準的開發,只是更為標準

  為了方便那些可能要在模擬環境中執行您的程式的使用者,開發軟體時需要緊記以下事項,並且開發任何軟體時都應該緊記這些事項:

  - 儘可能遵循適當的標準。
  - 避免“專門特性”。
  - 不要挑戰極限(push the envelope)。

  而且,只要可以避免,就不要依賴於一個月前剛剛釋出的某些東西來構建您的程式碼。因為那樣做將縮小您的有效的目標市場。

  參考資料

  - 您可以參閱本文在 developerWorks 全球站點上的 英文原文。

  - lxrun Linux 模擬器在 SCO 和 Solaris 系統上完全在使用者空間中執行,不需要修改核心。

  - Sun 維護著一個關於 在 Solaris 上使用 lxrun 的網頁。

  - IBM 紅皮書 Linux Applications on pSeries 討論到移植要勝於模擬,不過,移植的方法 —— 相容程式庫 —— 是實用的。

  - 伺服器診所: 在 Linux 上模擬老式作業系統 (developerWorks,2003 年 6 月)概述了針對 Linux 系統的作業系統模擬。

  - What to watch out for when writing portable shell scripts 一文中有更多關於可移植 shell 指令碼的資料。

  - 由於 WINE 不是模擬器(Is Not an Emulator),所以在一篇關於模擬的文章中引用它對它將是一種冒犯。

  - VirtualPC 支援 PC-on-PC 模擬。也有 VirtualPC for Macintosh。(由於 Microsoft 購買了這個產品,所以,沒有過多提及它在 Linux 上執行的可能性)。

  - VMWare 是最著名的虛擬機器模擬方案之一。

  - Serenity Virtual Station 是市場上的虛擬機器模擬方案之一。

  - Donn Seeley 於 2000 年在 Usenix 發表的 “LAP: a little language for OS emulation” 一文討論了為 BSD/OS 開發 Linux 模擬環境時遇到的問題。

  - 在 developerWorks Linux 專區 可以找到更多為 Linux 開發人員準備的參考資料。

  - 透過參與 developerWorks blogs 加入 developerWorks 社群。

  - 在 Developer Bookstore Linux 專欄中訂購打折出售的 Linux 書籍。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617731/viewspace-947552/,如需轉載,請註明出處,否則將追究法律責任。

相關文章